Javascript回调函数传递给Android
Posted
技术标签:
【中文标题】Javascript回调函数传递给Android【英文标题】:Javascript Callback function pass to Android 【发布时间】:2011-10-24 13:24:19 【问题描述】:我有一个用 Java 实现的 javascript 接口,由我在 webview 中加载的 javascript 代码调用。
JS Inside webview:
android.myFunction(function(data)
console.log(data);
);
Java:
public class JavaScriptInterface
Context context;
WebView webView;
JavaScriptInterface(Context c, WebView w)
context = c;
webView = w;
public void myFunction(String callback)
//when I log callback, it is "undefined"
String someData = "Yay for data";
String js =
"javascript:(function() "
+ "var callback = " + callback + ";"
+ "callback('" + someData + "');"
+ ")()";
webView.loadUrl(js);
webview 加载的字符串最终是:
javascript:(function() var callback = undefined; undefined();)()
我有几个想法:
一个。在 JS 中将回调构建为字符串。
b.在将回调传递给 Android.myFunction() 之前调用回调的 toString();
我的问题是,最好的方法是什么?我希望能够将对象传递给 Android,它神奇地工作。显然,情况并非如此。 ;) 下一个最好的方法是什么?
【问题讨论】:
将函数创建为字符串听起来像是纯粹的、蒸馏过的邪恶。 我完全同意。不幸的是,我很确定这是我在这种情况下的唯一选择。此外,我不确定是否有更好的方法来解决这个问题。我想要回调的灵活性,而不是仅仅写出一个函数 Android 端来处理回调。 @missingno 通过字符串操作创建函数有什么问题?我假设 Jonathan 会事先验证字符串,所以这看起来很合理。 【参考方案1】:我遇到了类似的问题:我想在网络应用中使用原生 Android 确认对话框。这意味着我必须使用确认对话框的结果从 Android 回调到 Javascript 部分。
我解决了这个问题:
function foo()
// user confirmation needed
var dataString = <encode data into string>;
MyClient.showConfirmationDialog('myCallBackFunction', dataString, 'A title', 'A message');
上面的代码调用了 Android javascript 接口(见下文)。 javascript 提供了回调方法myCallbackFunction()
,其名称作为参数传递给Android(连同数据字符串、标题和消息)。回调函数如下:
function myCallbackFunction(dataString, result)
var data = <decode data from dataString>;
if (result)
// user has confirmed
else
// user has denied
在Android端,我先在Activity的onCreate()
方法中激活Javascript接口:
public void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
WebView webView = new WebView(this);
setContentView(webView);
WebSettings settings = webView.getSettings();
settings.setJavaScriptEnabled(true);
webView.addJavascriptInterface(new MyJavascriptInterface(webView), "MyClient");
MyJavascriptInterface
的实现然后创建相应的 Android 对话框并将结果传递回 javascript:
WebView webView;
public MyJavascriptInterface(WebView w)
this.webView = w;
@JavascriptInterface
public void showConfirmationDialog(final String callbackFunction, final String data, String title,
String message)
Dialog.OnClickListener positiveListener = new Dialog.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
webView.loadUrl("javascript:" + callbackFunction + "('" + data + "', true)");
;
Dialog.OnClickListener negativeListener = new Dialog.OnClickListener()
@Override
public void onClick(DialogInterface dialog, int which)
webView.loadUrl("javascript:" + callbackFunction + "('" + data + "', false)");
;
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setTitle(title).setMessage(message).setPositiveButton("Ok", positiveListener)
.setNegativeButton("Cancel", negativeListener).setCancelable(false);
builder.create().show();
将回调函数的名称传递给 Android 允许使用多次调用确认对话框,每个确认对话框都配备了自己的函数来执行实际操作。数据字符串将携带执行操作所需的所有数据(甚至可以包含 Json 编码的对象)。
【讨论】:
这个答案值得更多提升(在我看来)。我几乎为这个“回调”功能挖掘了 PhoneGap 的源代码。但由于这个答案,我不必。 哇,用 javascript 字符串调用 loadUrl 真的是从 Java 调用(返回)到 Javascript 的唯一方法吗? MyJavascriptInterface 中的 webview 来自哪里??【参考方案2】:您将无法按照指定的方式传递函数。您将一个函数传递给 Android.myData,但 Android.myData 需要一个字符串。相反,您可能想要
var myCallback = console.log;
Android.myFunction("myCallback");
您仍然有一个问题,即您没有将任何数据传递给回调。虽然这与您的问题没有直接关系,但它将成为一个问题,因为您将有相同的字符串转换问题(可通过 JSON 解决......但如果 Android 为您处理这部分会很好)。
最后,您可以将 javascript: 字符串缩短为
String js = "javascript:" + callback + "();";
但是,当然,先测试;)
【讨论】:
这是我终于意识到的。它应该更明显。将要解析为 javascript 的字符串从 Android 注入到 Webview 中,显然是远远超出范围......吻那个闭包再见。至于第二个,我编辑了问题以纠正这个错误。这就是我在没有先测试的情况下发布我的代码的缩写版本的结果。【参考方案3】:WebView 允许您在窗口上下文中直接执行一些 JavaScript。 所以你不需要通过资源 URL 传递 JavaScript。
这是一种将数据传回 html 页面的经过批准的方式
/**
* This is an approved way to pass data back to the html page
*/
webView.evaluateJavascript("alert('pass here some ...')", new ValueCallback<String>()
@Override
public void onReceiveValue(String s)
);
来自官方文档的详细信息
在当前显示页面的上下文中异步评估 JavaScript。如果非空,|resultCallback|将使用从该执行返回的任何结果调用。此方法必须在 UI 线程上调用,回调将在 UI 线程上进行。
兼容性说明。面向 N 或更高版本的应用程序,来自空 WebView 的 JavaScript 状态不再在诸如 loadUrl(String) 之类的导航中保持不变。例如,调用 loadUrl(String) 之前定义的全局变量和函数将不会存在于加载的页面中。应用程序应该使用 addJavascriptInterface(Object, String) 来跨导航保存 JavaScript 对象。
Link to the official WebView documentation
【讨论】:
以上是关于Javascript回调函数传递给Android的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript:如何将多个参数传递给对象成员内的回调函数?
如何在 Javascript .filter() 方法中将额外参数传递给回调函数?