Chcę uzyskać wartość zwracaną przez JavaScript w systemie Android. Mogę to zrobić na iPhonie, ale nie mogę na Androidzie. Użyłem loadUrl, ale zwrócił on void zamiast obiektu. Czy ktoś może mi pomóc?
83
Taka sama, Keith
ale krótsza odpowiedź
webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");
I zaimplementuj funkcję
@JavascriptInterface
public void onData(String value) {
//.. do something with the data
}
Nie zapomnij usunąć onData
z proguard
listy (jeśli masz włączony proguard)
proguard
część?document.getElementById("my-div").scrollTop
aby uzyskać pozycję przewijania zSwipeRefreshLayout::canChildScrollUp()
. Podejrzewam, że może to być spowodowane zbyt częstym dzwonieniem w krótkim okresie. lubproguard
co podejrzewam, bo po prostu nie wiem, co to jest ..Oto hack, jak możesz to osiągnąć:
Dodaj tego klienta do swojego 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; } }
Teraz w wywołaniu javascript wykonaj:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
Teraz w wywołaniu onJsAlert "wiadomość" będzie zawierać zwróconą wartość.
źródło
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
zamiast,onJsAlert
a następnie w wywołaniu javascript, które robiszwebView.loadUrl("javascript:console.log(functionThatReturnsSomething)");
- w ten sposób pozostawiasz alerty JS w spokoju.WebChromeClient.onConsoleMessage
wydaje się być czystsze, ale należy pamiętać, że nie działa z niektórymi urządzeniami HTC. Zobacz to pytanie, aby uzyskać więcej informacji.mWebView.addJavascriptInterface(YourObject mYourObject,String yourNameForObject);
, wywołując funkcjęmWebView.loadUrl("javascript:yourNameForObject.yourSetterMethod(valueToSet)")
Służy
addJavascriptInterface()
do dodawania obiektu Java do środowiska Javascript. Niech JavaScript wywoła metodę na tym obiekcie Java, aby podać jego „wartość zwracaną”.źródło
loadUrl("javascript:...")
(Poziom API 1-18) lubevaluateJavascript()
(Poziom API 19+), aby ocenić własny JavaScript w kontekście aktualnie załadowanej strony internetowej.Oto, co dziś wymyśliłem. Jest bezpieczny dla wątków, rozsądnie wydajny i umożliwia synchroniczne wykonywanie JavaScriptu z Java dla Android WebView .
Działa na Androidzie 2.2 i nowszych. (Wymaga commons-lang, ponieważ potrzebuję fragmentów kodu przekazywanych do eval () jako ciągu JavaScript. Możesz usunąć tę zależność, zawijając kod nie w cudzysłów, ale w
function(){}
)Najpierw dodaj to do swojego pliku 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); }
Następnie dodaj to do swojej aktywności w Androidzie:
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); } }
źródło
function(){}
? Jak umieścić jsString w{}
?W przypadku API 19+ najlepszym sposobem na to jest wywołanie compareJavascript w swoim WebView:
webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() { @Override public void onReceiveValue(String value) { // value is the result returned by the Javascript as JSON } });
Powiązana odpowiedź z bardziej szczegółowymi informacjami: https://stackoverflow.com/a/20377857
źródło
Rozwiązanie, które zasugerował @Felix Khazin, działa, ale brakuje jednego kluczowego punktu.
Wywołanie javascript należy wykonać po
WebView
załadowaniu strony internetowej w . Dodaj toWebViewClient
doWebView
, wraz zWebChromeClient
.Pełny przykład:
@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; } }
źródło
Jako alternatywny wariant korzystający ze schematu niestandardowego:
Główna aktywność
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 (znajduje się w zwiniętych zasobach)
<!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>
źródło
Możesz to zrobić w ten sposób:
[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); } }
źródło