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?
Antworten:
Gleich wie Keithaber kürzere Antwort
webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");
Und implementieren Sie die Funktion
@JavascriptInterface
public void onData(String value) {
//.. do something with the data
}
Vergessen Sie nicht , entfernen die onDataaus proguardListe (wenn Sie aktiviert proguard)
document.getElementById("my-div").scrollTop, um die Bildlaufposition zu erhalten SwipeRefreshLayout::canChildScrollUp(). Ich vermute, es könnte daran liegen, dass der Anruf in kurzer Zeit zu oft angerufen wird. oder proguardwas 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.
public boolean onConsoleMessage(ConsoleMessage consoleMessage)anstelle von onJsAlertund dann in dem von Ihnen ausgeführten Javascript-Aufruf verwenden. Auf webView.loadUrl("javascript:console.log(functionThatReturnsSomething)");diese Weise lassen Sie die JS-Warnungen in Ruhe.
WebChromeClient.onConsoleMessagescheint 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.
loadUrl("javascript:...")(API Level 1-18) oder evaluateJavascript()(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);
}
}
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
Die von @Felix Khazin vorgeschlagene Lösung funktioniert, aber es fehlt ein wichtiger Punkt.
Der Javascript-Aufruf sollte nach dem WebViewLaden der Webseite in erfolgen . Fügen Sie diese WebViewClientauf die WebView, zusammen mit der WebChromeClient.
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;
}
}
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>
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);
}
}
proguard?