Tôi muốn nhận giá trị trả về từ Javascript trong Android. Tôi có thể làm điều đó với iPhone, nhưng tôi không thể với Android. Tôi đã sử dụng loadUrl, nhưng nó trả về void thay vì một đối tượng. Ai có thể giúp tôi?
Câu trả lời:
Giống như Keith
câu trả lời nhưng ngắn hơn
webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");
Và thực hiện chức năng
@JavascriptInterface
public void onData(String value) {
//.. do something with the data
}
Đừng quên xóa danh sách onData
khỏi proguard
danh sách (nếu bạn đã bật proguard)
document.getElementById("my-div").scrollTop
để có được vị trí cuộn từ SwipeRefreshLayout::canChildScrollUp()
. Tôi nghi ngờ có thể do cuộc gọi bị gọi quá nhiều lần trong thời gian ngắn. hay proguard
mà tôi nghi ngờ vì tôi chỉ không biết nó là gì ..
Đây là một bí quyết về cách bạn có thể thực hiện nó:
Thêm Ứng dụng khách này vào WebView của bạn:
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;
}
}
Bây giờ trong lệnh gọi javascript của bạn, hãy làm:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
Bây giờ trong lời gọi onJsAlert, "thông báo" sẽ chứa giá trị trả về.
public boolean onConsoleMessage(ConsoleMessage consoleMessage)
thay vì onJsAlert
và sau đó trong lệnh gọi javascript mà bạn thực hiện webView.loadUrl("javascript:console.log(functionThatReturnsSomething)");
- theo cách đó bạn để yên các cảnh báo JS.
WebChromeClient.onConsoleMessage
có vẻ sạch hơn nhưng lưu ý rằng nó không hoạt động với một số thiết bị HTC. Xem câu hỏi này để biết thêm thông tin.
mWebView.addJavascriptInterface(YourObject mYourObject,String yourNameForObject);
bằng cách gọi hàmmWebView.loadUrl("javascript:yourNameForObject.yourSetterMethod(valueToSet)")
Sử dụng addJavascriptInterface()
để thêm một đối tượng Java vào môi trường Javascript. Yêu cầu Javascript của bạn gọi một phương thức trên đối tượng Java đó để cung cấp "giá trị trả về" của nó.
loadUrl("javascript:...")
(API cấp 1-18) hoặc evaluateJavascript()
(API cấp 19+) để đánh giá JavaScript của riêng bạn trong ngữ cảnh của trang Web hiện đang tải.
Đây là những gì tôi nghĩ ra ngày hôm nay. Nó an toàn theo luồng, hiệu quả hợp lý và cho phép thực thi Javascript đồng bộ từ Java cho Android WebView .
Hoạt động trên Android 2.2 trở lên. (Yêu cầu commons-lang vì tôi cần các đoạn mã của mình được chuyển đến eval () dưới dạng một chuỗi Javascript. Bạn có thể loại bỏ sự phụ thuộc này bằng cách đặt mã không phải trong dấu ngoặc kép mà ở trong function(){}
)
Đầu tiên, thêm cái này vào tệp Javascript của bạn:
function evalJsForAndroid(evalJs_index, jsString) {
var evalJs_result = "";
try {
evalJs_result = ""+eval(jsString);
} catch (e) {
console.log(e);
}
androidInterface.processReturnValue(evalJs_index, evalJs_result);
}
Sau đó, thêm cái này vào hoạt động Android của bạn:
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(){}
? Làm thế nào để đặt jsString vào {}
?
Trên API 19+, cách tốt nhất để làm điều này là gọi evalJavascript trên WebView của bạn:
webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() {
@Override public void onReceiveValue(String value) {
// value is the result returned by the Javascript as JSON
}
});
Câu trả lời liên quan với chi tiết hơn: https://stackoverflow.com/a/20377857
Giải pháp mà @Felix Khazin đề xuất hoạt động, nhưng thiếu một điểm chính.
Lệnh gọi javascript phải được thực hiện sau khi trang web trong WebView
tệp được tải. Thêm cái này WebViewClient
vào WebView
, cùng với WebChromeClient
.
Ví dụ đầy đủ:
@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;
}
}
Là một biến thể thay thế sử dụng lược đồ tùy chỉnh:
Hoạt động chủ yêu
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 (nằm trong phần tử được gấp lại)
<!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>
Bạn có thể làm như thế này:
[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
một phần?