【发布时间】:2011-03-18 22:27:33
【问题描述】:
我想从 Android 中的 Javascript 获取返回值。我可以用 iPhone 做到这一点,但我不能用 Android。我使用了 loadUrl,但它返回的是 void 而不是一个对象。有人可以帮帮我吗?
【问题讨论】:
我想从 Android 中的 Javascript 获取返回值。我可以用 iPhone 做到这一点,但我不能用 Android。我使用了 loadUrl,但它返回的是 void 而不是一个对象。有人可以帮帮我吗?
【问题讨论】:
与Keith 相同,但答案更短
webView.addJavascriptInterface(this, "android");
webView.loadUrl("javascript:android.onData(functionThatReturnsSomething)");
并实现功能
@JavascriptInterface
public void onData(String value) {
//.. do something with the data
}
不要忘记从proguard 列表中删除onData(如果您启用了proguard)
【讨论】:
proguard 部分吗?
document.getElementById("my-div").scrollTop 以从 SwipeRefreshLayout::canChildScrollUp() 获取滚动位置。我怀疑这可能是由于电话在短时间内被调用太多次。或proguard 我怀疑是因为我只是不知道它是什么..
这里有一个关于如何实现它的技巧:
将此客户端添加到您的 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;
}
}
现在在你的 javascript 调用中做:
webView.loadUrl("javascript:alert(functionThatReturnsSomething)");
现在在 onJsAlert 调用中的“消息”将包含返回值。
【讨论】:
public boolean onConsoleMessage(ConsoleMessage consoleMessage) 而不是onJsAlert 拦截JS 警报的情况下获得相同的结果,然后在javascript 调用中执行webView.loadUrl("javascript:console.log(functionThatReturnsSomething)"); - 这样您就可以不理会JS 警报了。
WebChromeClient.onConsoleMessage 的解决方案似乎更简洁,但请注意它不适用于某些 HTC 设备。请参阅this question 了解更多信息。
mWebView.loadUrl("javascript:yourNameForObject.yourSetterMethod(valueToSet)") 来调用传递给 mWebView.addJavascriptInterface(YourObject mYourObject,String yourNameForObject); 的对象的方法
使用addJavascriptInterface() 将Java 对象添加到Javascript 环境。让您的 Javascript 调用该 Java 对象上的方法以提供其“返回值”。
【讨论】:
loadUrl("javascript:...")(API 级别 1-18)或evaluateJavascript()(API 级别 19+)在当前加载的网页上下文中评估您自己的 JavaScript。跨度>
这就是我今天想出的。它是线程安全的、相当高效的,并且允许从 Java 为 Android WebView 同步 Javascript 执行。
适用于 Android 2.2 及更高版本。 (需要 commons-lang,因为我需要将我的代码 sn-ps 作为 Javascript 字符串传递给 eval()。您可以通过将代码不用引号括起来,而是用 function(){} 括起来来删除这种依赖关系)
首先,将其添加到您的 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);
}
然后,将其添加到您的 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(){}?如何将 jsString 放入{}?
在 API 19+ 上,最好的方法是在您的 WebView 上调用 evaluateJavascript:
webView.evaluateJavascript("foo.bar()", new ValueCallback<String>() {
@Override public void onReceiveValue(String value) {
// value is the result returned by the Javascript as JSON
}
});
更详细的相关答案:https://stackoverflow.com/a/20377857
【讨论】:
@Felix Khazin 建议的解决方案可行,但缺少一个关键点。
应在WebView 中的网页加载后进行javascript 调用。将此WebViewClient 与WebChromeClient 一起添加到WebView。
完整示例:
@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;
}
}
【讨论】:
作为使用 自定义方案 与Android native code <-> HTML/JS code 通信的替代变体。例如 MRAID 使用这种技术[About]
MainActivity
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(位于折叠的资产中)
<!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>
【讨论】:
你可以这样做:
[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);
}
}
【讨论】: