關(guān)鍵類
- WebView
- WebSettings
- WebViewClient
- WebChromeClient
WebView基本用法:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");
如果加載的是網(wǎng)絡(luò)頁面需要申請網(wǎng)絡(luò)權(quán)限:
<uses-permission android:name="android.permission.INTERNET" />
補(bǔ)充
- WebView還有兩個(gè)方法,
loadData(String data, String miniType,String edcoding)和loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl).有時(shí)候loadData()只能加載‘data’,會(huì)導(dǎo)致其他協(xié)議的URL無法加載,當(dāng)加載的URL不一定是‘data’時(shí)推薦用后一個(gè)方法。- mimeType: 數(shù)據(jù)類型,如:text/html.
- encoding: 數(shù)據(jù)編碼方式 base64 或者 url encoding.
- baseUrl: 指定頁面的根路徑.
-
URL統(tǒng)一資源定位符(uniform resource locator),URI統(tǒng)一資源標(biāo)識(shí)符(uniform resource identifier )。URI包括URL。URL的一般語法scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]。
配置WebView
配置WebView,需要先獲得一個(gè)WebSettings對象。WebSettings對象并不是通過new來獲得,而是在我們創(chuàng)建WebView的時(shí)候,就會(huì)獲得一個(gè)默認(rèn)的WebSettings對象。這個(gè)WebSetting對象可以通過myWebView.getSettings()來獲得。
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
當(dāng)我們通過WebView來加載了一個(gè)頁面時(shí),點(diǎn)擊頁面上的鏈接時(shí),會(huì)彈出一個(gè)對話框,讓我們選擇通過哪個(gè)瀏覽器來打開,如果我們希望直接在自己的WebView中打開,就可以通過如下方法實(shí)現(xiàn):
myWebView.setWebViewClient(new WebViewClient());
WebView攔截資源請求
有時(shí)候我們不希望自己的WebView處理相關(guān)的請求,例如頁面中具有發(fā)郵件,打電話,發(fā)消息這類鏈接的時(shí)候,我們希望用戶點(diǎn)擊之后會(huì)啟動(dòng)第三方應(yīng)用,而不是我們自己的WebView處理,就可以通過如下方式實(shí)現(xiàn)。
首先我將一個(gè)html文檔放在了main/assets目錄下,注意不是res/目錄下。模擬一個(gè)網(wǎng)頁。html文檔如下:
<!DOCTYPE html>
<html>
<head>
<title>WebView Test</title>
<!--下面前兩個(gè)方法通過javascript調(diào)用WebView中的java代碼-->
<!--第三個(gè)方法,就是簡單的javascript代碼,在網(wǎng)頁打開,會(huì)有一個(gè)警告對話框-->
<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>
<!--兩個(gè)綁定點(diǎn)擊事件的按鈕-->
<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處理,會(huì)調(diào)用第三方應(yīng)用。
// 注意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);
補(bǔ)充
- 當(dāng)我們想要屏蔽掉網(wǎng)頁的某些資源的時(shí)候,需要重寫WebViewClient的
shouldIntercepterRequest()方法,而重寫shouldOverrideUrlLoading是沒有效果的。因?yàn)榫W(wǎng)頁的資源是在"IO"線程里加載的,而shouldOverrideUrlLoading運(yùn)行在主線程,只能攔截新的URL對象,也就是頁面需要重寫加載的時(shí)候,才會(huì)回調(diào)。而shouldIntercepterRequest方法運(yùn)行在IO線程里,可以對資源請求進(jìn)行攔截,并且可以返回其他的資源。 - 禁止加載圖片
webSettings.setLoadsImagesAutomatically(false) - 當(dāng)頁面載入錯(cuò)誤時(shí),可以重寫
WebViewClient的onReceivedError()方法。
JavaScript和WebView的交互
Jave調(diào)用Javascript
直接調(diào)用
myWebView.loadUrl("javascript:alert(java to javascript)");
補(bǔ)充
也可以通過evaluateJavascript方法來處理帶有返回值的js方法。
通過重載WebChromeClient調(diào)用
注意上面的Html代碼,當(dāng)頁面加載時(shí)會(huì)有一個(gè)彈出對話框。雖然已給WebView設(shè)置里setJavaScriptEnabled(true),但是WebView依然無法顯示對話框。通過如下方法就可使對話框顯示。
myWebView.setWebChromeClient(new WebChromeClient());
那么WebChromeClient和WebViewClient有什么不同呢?前者主要負(fù)責(zé)輔助處理JS,與頁面內(nèi)容交互。后者主要負(fù)責(zé)頁面加載過程中的事件通知。
如果你覺得這個(gè)彈窗實(shí)在太難看了,我們可以通過如下方法,重新自定義:
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調(diào)用java
主要是通過addJavascriptInterface(Object object,String name),向Javascript中注入對象和對象的名字。在api17以下會(huì)注入所有public方法,api17以上只會(huì)注入添加了@JavascriptInterface注釋的方法。
首先我們創(chuàng)建一個(gè)類,如下:
public class WebAppInterface {
private Context mContext;
private final static int NOTIFICATION_ID = 1;
public WebAppInterface(Context c) {
mContext = c;
}
// 對應(yīng)html第一個(gè)方法
@JavascriptInterface
public void newActivity(){
Intent intent = new Intent(mContext,JSActivity.class);
mContext.startActivity(intent);
}
// 對應(yīng)html中第二個(gè)方法
@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添加這個(gè)js接口
myWebView.addJavascriptInterface(new WebAppInterface(mContext),"android");
之后就可以通過js調(diào)用上面設(shè)置的兩個(gè)方法了。詳細(xì)信息請參考上面的html文件。
WebView小拓展
如果我們不希望用戶點(diǎn)擊了WebView中的鏈接跳轉(zhuǎn)之后,按下返回鍵直接退出應(yīng)用,可以在Activity中重寫onBackPress方法
@Override
public void onBackPressed() {
if (myWebView.canGoBack()){
myWebView.goBack();
}else {
super.onBackPressed();
}
}
WebView調(diào)試技巧
添加如下代碼
if (Build.VERSION.SDK_INT >=Build.VERSION_CODES.KITKAT && BuildConfig.DEBUG){
myWebView.setWebContentsDebuggingEnabled(true);
}
在chrome瀏覽器中輸入chrome//inspect/#devices.