总结:
APK中:
1.调用JS关键代码:
//调用JS方法,并传递参数
mWebView.loadUrl("javascript:invokedByJava('java_data')");
2.1 网页端:
<input type="button" value="调用Java方法" οnclick="window.stub.jsMethod('来至JS的参数');" />
2.2 APK端:
/*
绑定Java对象到WebView,这样可以让JS与Java通信(JS访问Java方法)
第一个参数是自定义类对象,映射成JS对象
第二个参数是第一个参数的JS别名
调用示例:
mWebView.loadUrl("javascript:window.stub.jsMethod('param')");
*/
mWebView.addJavascriptInterface(new JsToJava(), "stub");
private class JsToJava {
@JavascriptInterface
public void jsMethod(String paramFromJS) {
Log.i("CDH", paramFromJS);
}
}
转:http://blog.youkuaiyun.com/chenfeng0104/article/details/7023448
这篇文章讲了一些WebView的使用方法,在项目中,常常会使用到,尤其是需要与JS交互。
效果图
点击“调用alert”按钮,在Android中捕获JS alert,并用Android组件(AlertDialog)替换
点击“调用Java方法”按钮,在JS中调用并传递参数到Java中的方法
点击“调JS方法”按钮(这个按钮不是html元素,而是android元素),从Java端调用html中的JS方法,并传递参数到JS方法中。
完整代码
在assets目录下创建一个html文件来模拟WebView访问的内容
编辑js_interact_demo.html内容如下
<html>
<head>
<title>JS交互</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<script type="text/javascript">
function invokedByJava(param) {
document.getElementById("content").innerHTML = "Java has invoked JS function and returnd the data:"+param;
}
</script>
</head>
<body>
<p id="content"></p>
<p>
<input type="button" value="调用Java方法" οnclick="window.stub.jsMethod('来至JS的参数');" />
<input type="button" value="调用alert" οnclick="alert('hello')" />
</p>
</body>
</html>
在res/layout目录下创建web_view.xml布局文件,内容如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:id="@+id/web_view_invoke_js"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="调JS方法"/>
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content">
<EditText android:id="@+id/web_view_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button android:id="@+id/web_view_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="浏览"/>
</LinearLayout>
<WebView android:id="@+id/web_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
创建名为WebViewDemo的Activity文件
public class WebViewDemo extends Activity {
private WebView mWebView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.web_view);
findViewById(R.id.web_view_invoke_js).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//调用JS方法,并传递参数
mWebView.loadUrl("javascript:invokedByJava('java_data')");
}
});
mWebView = (WebView)findViewById(R.id.web_view);
mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
mWebView.getSettings().setBuiltInZoomControls(true);
mWebView.getSettings().setJavaScriptEnabled(true);
/*
WebView默认用系统自带浏览器处理页面跳转。
为了让页面跳转在当前WebView中进行,重写WebViewClient。
但是按BACK键时,不会返回跳转前的页面,而是退出本Activity。重写onKeyDown()方法来解决此问题。
*/
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);//使用当前WebView处理跳转
return true;//true表示此事件在此处被处理,不需要再广播
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//有页面跳转时被回调
}
@Override
public void onPageFinished(WebView view, String url) {
//页面跳转结束后被回调
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
Toast.makeText(WebViewDemo.this, "Oh no! " + description, Toast.LENGTH_SHORT).show();
}
});
/*
当WebView内容影响UI时调用WebChromeClient的方法
*/
mWebView.setWebChromeClient(new WebChromeClient() {
/**
* 处理JavaScript Alert事件
*/
@Override
public boolean onJsAlert(WebView view, String url,
String message, final JsResult result) {
//用Android组件替换
new AlertDialog.Builder(WebViewDemo.this)
.setTitle("JS提示")
.setMessage(message)
.setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
})
.setCancelable(false)
.create().show();
return true;
}
});
/*
绑定Java对象到WebView,这样可以让JS与Java通信(JS访问Java方法)
第一个参数是自定义类对象,映射成JS对象
第二个参数是第一个参数的JS别名
调用示例:
mWebView.loadUrl("javascript:window.stub.jsMethod('param')");
*/
mWebView.addJavascriptInterface(new JsToJava(), "stub");
final EditText mEditText = (EditText)findViewById(R.id.web_view_text);
findViewById(R.id.web_view_search).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
String url = mEditText.getText().toString();
if (url == null || "".equals(url)) {
Toast.makeText(WebViewDemo.this, "请输入URL", Toast.LENGTH_SHORT).show();
} else {
if (!url.startsWith("http:") && !url.startsWith("file:")) {
url = "http://" + url;
}
mWebView.loadUrl(url);
}
}
});
//默认页面
mWebView.loadUrl("file:///android_asset/js_interact_demo.html");
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//处理WebView跳转返回
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
mWebView.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
private class JsToJava {
public void jsMethod(String paramFromJS) {
Log.i("CDH", paramFromJS);
}
}
}
[Android] Web Console: Uncaught TypeError: Object [object Object] has no method 'xxx'
转:http://blog.youkuaiyun.com/arui319/article/details/18556669
我们开发的产品,有一部分功能,需要在WebView中打开web页面,然后在web页面中通过js方法回调部分native的功能。
对于web回调native的开发方式,如果不了解的话,可以参考我以前的一篇博文《Android中Webview使用自定义的javascript进行回调》http://blog.csdn.NET/arui319/article/details/7044638
最近测试发现,在某些最新机型上(4.2及以上),JS回调好像不起做用了。打开log,提示Uncaught TypeError: Object [object Object] has no method 'xxx' 。其中xxx就是web页面中写的js方法名。
仔细研究,发现是因为Android4.2及以上版本对于js的支持方式有改变导致(又是一起新版本导致的不兼容事件,最近这种事情越来越多了)。具体的,请看下面这篇文章,写的很详细了,没有必要再写一遍了,请直接参考吧。http://blog.youkuaiyun.com/zgjxwl/article/details/9627685
记录于此,方便网友查询。
WebView注入Java对象注意事项
转:http://blog.youkuaiyun.com/zgjxwl/article/details/9627685
在android4.2以前,注入步骤如下:
webview.getSetting().setJavaScriptEnable(true);
class JsObject {
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
Android4.2及以后,注入步骤如下:
webview.getSetting().setJavaScriptEnable(true);
class JsObject {
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
发现区别没?4.2之前向webview注入的对象所暴露的接口toString没有注释语句@JavascriptInterface,而4.2及以后的则多了注释语句@JavascriptInterface
webview.getSetting().setJavaScriptEnable(true);
class JsObject {
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
经过查官方文档所知,因为这个接口允许JavaScript 控制宿主应用程序,这是个很强大的特性,但同时,在4.2的版本前存在重大安全隐患,因为JavaScript 可以使用反射访问注入webview的Java对象的public fields,在一个包含不信任内容的WebView中使用这个方法,会允许攻击者去篡改宿主应用程序,使用宿主应用程序的权限执行java代码。因此4.2以后,任何为JS暴露的接口,都需要加
@JavascriptInterface
注释,这样,这个Java对象的fields 将不允许被JS访问。
官方文档说明:
From the Android 4.2 documentation:
Caution: If you've set your targetSdkVersion to 17 or higher, you must add the @JavascriptInterface annotation to any method that you want available your web page code (the method must also be public). If you do not provide the annotation, then the method will not accessible by your web page when running on Android 4.2 or higher.
注:如果将targetSdkVersion 设置为17或者更高,但却没有给暴露的js接口加@JavascriptInterface注释,则logcat会报如下输出:E/Web Console: Uncaught TypeError: Object [object Object] has no method 'toString'
public void addJavascriptInterface (Object object, String name)
Injects the supplied Java object into this WebView. The object is injected into the JavaScript context of the main frame, using the supplied name. This allows the Java object's methods to be accessed from JavaScript. For applications targeted to API level JELLY_BEAN_MR1
and above, only public methods that are annotated with JavascriptInterface
can be accessed from JavaScript. For applications targeted to API level JELLY_BEAN
or below, all public methods (including the inherited ones) can be accessed, see the important security note below for implications.
Note that injected objects will not appear in JavaScript until the page is next (re)loaded. For example:
class JsObject {
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
webView.loadData("", "text/html", null);
webView.loadUrl("javascript:alert(injectedObject.toString())");
IMPORTANT:
- This method can be used to allow JavaScript to control the host application. This is a powerful feature, but also presents a security risk for applications targeted to API level
JELLY_BEAN
or below, because JavaScript could use reflection to access an injected object's public fields. Use of this method in a WebView containing untrusted content could allow an attacker to manipulate the host application in unintended ways, executing Java code with the permissions of the host application. Use extreme care when using this method in a WebView which could contain untrusted content. - JavaScript interacts with Java object on a private, background thread of this WebView. Care is therefore required to maintain thread safety.
- The Java object's fields are not accessible.