关键类
- WebView
- WebSettings
- WebViewClient
- WebChromeClient
WebView基本用法:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");
如果加载的是网络页面需要申请网络权限:
<uses-permission android:name="android.permission.INTERNET" />
补充
- WebView还有两个方法,
loadData(String data, String miniType,String edcoding)
和loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)
.有时候loadData()
只能加载‘data’,会导致其他协议的URL无法加载,当加载的URL不一定是‘data’时推荐用后一个方法。- mimeType: 数据类型,如:text/html.
- encoding: 数据编码方式 base64 或者 url encoding.
- baseUrl: 指定页面的根路径.
-
URL
统一资源定位符(uniform resource locator),URI
统一资源标识符(uniform resource identifier )。URI包括URL。URL
的一般语法scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
。
配置WebView
配置WebView,需要先获得一个WebSettings对象。WebSettings对象并不是通过new
来获得,而是在我们创建WebView的时候,就会获得一个默认的WebSettings对象。这个WebSetting对象可以通过myWebView.getSettings()
来获得。
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
当我们通过WebView来加载了一个页面时,点击页面上的链接时,会弹出一个对话框,让我们选择通过哪个浏览器来打开,如果我们希望直接在自己的WebView中打开,就可以通过如下方法实现:
myWebView.setWebViewClient(new WebViewClient());
WebView拦截资源请求
有时候我们不希望自己的WebView处理相关的请求,例如页面中具有发邮件,打电话,发消息这类链接的时候,我们希望用户点击之后会启动第三方应用,而不是我们自己的WebView处理,就可以通过如下方式实现。
首先我将一个html文档放在了main/assets
目录下,注意不是res/
目录下。模拟一个网页。html文档如下:
<!DOCTYPE html>
<html>
<head>
<title>WebView Test</title>
<!--下面前两个方法通过javascript调用WebView中的java代码-->
<!--第三个方法,就是简单的javascript代码,在网页打开,会有一个警告对话框-->
<script type="text/javascript">
var new_activity = function(){
android.newActivity();
}
var send_notification = function(){
android.sendNotification();
}
window.onload = function(){
alert("alert from javascript");
}
</script>
</head>
<body>
<p><a href="mailto: study@163.com">send email</a></p>
<p><a href="tel: 12312312312">call</a></p>
<p><a href="sms: 10086">send message</a></p>
<!--两个绑定点击事件的按钮-->
<button onclick="new_activity()">new activity</button>
<button onclick="send_notification()">send notification</button>
</body>
</html>
在java代码中重写WebViewClient的shouldOverrideUrlLoading(WebView view, String url)
方法,该方法返回true
,表示重写了该方法,这次请求不由自己的WebView
处理,会调用第三方应用。
// 注意url的写法。
String url = "file:///android_asset/index_test.html";
myWebView.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Uri uri = Uri.parse(url);
if ("mailto".equalsIgnoreCase(uri.getScheme())
||"tel".equalsIgnoreCase(uri.getScheme())
||"sms".equalsIgnoreCase(uri.getScheme())){
//注意这里Intent Action的写法。
Intent intent=new Intent(Intent.ACTION_VIEW, uri);
startActivity( intent);
return true;
}
return false;
}
});
myWebView.loadUrl(url);
补充
- 当我们想要屏蔽掉网页的某些资源的时候,需要重写WebViewClient的
shouldIntercepterRequest()
方法,而重写shouldOverrideUrlLoading
是没有效果的。因为网页的资源是在"IO"线程里加载的,而shouldOverrideUrlLoading
运行在主线程,只能拦截新的URL
对象,也就是页面需要重写加载的时候,才会回调。而shouldIntercepterRequest
方法运行在IO
线程里,可以对资源请求进行拦截,并且可以返回其他的资源。 - 禁止加载图片
webSettings.setLoadsImagesAutomatically(false)
- 当页面载入错误时,可以重写
WebViewClient
的onReceivedError()
方法。
JavaScript和WebView的交互
Jave调用Javascript
直接调用
myWebView.loadUrl("javascript:alert(java to javascript)");
补充
也可以通过evaluateJavascript
方法来处理带有返回值的js方法。
通过重载WebChromeClient调用
注意上面的Html代码,当页面加载时会有一个弹出对话框。虽然已给WebView设置里setJavaScriptEnabled(true)
,但是WebView依然无法显示对话框。通过如下方法就可使对话框显示。
myWebView.setWebChromeClient(new WebChromeClient());
那么WebChromeClient
和WebViewClient
有什么不同呢?前者主要负责辅助处理JS,与页面内容交互。后者主要负责页面加载过程中的事件通知。
如果你觉得这个弹窗实在太难看了,我们可以通过如下方法,重新自定义:
myWebView.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Toast.makeText(MainActivity.this,message,Toast.LENGTH_SHORT).show();
result.confirm();
return true;
}
});
Javascript调用java
主要是通过addJavascriptInterface(Object object,String name)
,向Javascript中注入对象和对象的名字。在api17以下会注入所有public
方法,api17以上只会注入添加了@JavascriptInterface
注释的方法。
首先我们创建一个类,如下:
public class WebAppInterface {
private Context mContext;
private final static int NOTIFICATION_ID = 1;
public WebAppInterface(Context c) {
mContext = c;
}
// 对应html第一个方法
@JavascriptInterface
public void newActivity(){
Intent intent = new Intent(mContext,JSActivity.class);
mContext.startActivity(intent);
}
// 对应html中第二个方法
@JavascriptInterface
public void sendNotification(){
Notification notification = new NotificationCompat.Builder(mContext)
.setContentTitle("hello")
.setContentText("this notification is sent by js")
.setSmallIcon(R.drawable.notification_icon)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL)
.build();
NotificationManager manager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(NOTIFICATION_ID,notification);
}
}
然后为WebView添加这个js接口
myWebView.addJavascriptInterface(new WebAppInterface(mContext),"android");
之后就可以通过js调用上面设置的两个方法了。详细信息请参考上面的html文件。
WebView小拓展
如果我们不希望用户点击了WebView中的链接跳转之后,按下返回键直接退出应用,可以在Activity中重写onBackPress
方法
@Override
public void onBackPressed() {
if (myWebView.canGoBack()){
myWebView.goBack();
}else {
super.onBackPressed();
}
}
WebView调试技巧
添加如下代码
if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.KITKAT && BuildConfig.DEBUG){
myWebView.setWebContentsDebuggingEnabled(true);
}
在chrome浏览器中输入chrome//inspect/#devices
.