談談WebView的使用【從零開始搭建android框架系列(5)】
更多及時技術資訊,歡迎關注我的微博 :Anthony
本篇文章項目github地址:MVPCommon
本文章原地址:簡書博客
1 前言
這篇文章將從webview的基礎,介紹到項目中的真實使用。以及怎麼樣通過注入js腳本的方式來改變網頁內容,從而在本地展示新聞體育列表。製作出一個像模像樣的app。
嚴正聲明,網頁數據來自 虎撲體育,僅作學習用途,請勿在任何商業用途中使用。
2 webview基礎
WebView是手機中內置了一款高性能 webkit 內核瀏覽器,在 SDK 中封裝的一個組件。沒有提供地址欄和導航欄,WebView只是單純的展示一個網頁界面。在開發中經常都會用到。
Android4.4(API版本19)引入了新的一個基於Chromium版本的新版本WebView。該變化提高了WebView的性能,並且和最新的Web瀏覽器支持最新的HTML5,CSS3樣式以及Javascript標準。當在 Android 4.4或者更高的版本上面運行時,任何使用WebView的application會繼承使用這些特性。本文章主要描述了一下WebView的新特性。如果你設置targetSdkVersion爲19或者更高時,那你就需要特別的注意。這裏不做過多講解,參考Migrating to WebView in Android 4.4(官網)
2.1 添加webview到應用中
直接將webview添加到layout文件中
<?xml version="1.0" encoding="utf-8"?>
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
使用webview加載url使用loadUrl方法:
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.loadUrl("http://www.example.com");
AndroidManifest.xml 中必須添加訪問網絡權限。
<manifest ... >
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
2.2 支持javascript
如果訪問的頁面中有 Javascript,則 WebView 初始化的時候必須設置支持 Javascript。(WebSetting中提供了很多有用的api, 點擊鏈接查看)
WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
通過創建JavaScript的接口可以讓JavaScript和安卓客戶端進行交互。比如說JavaScript可以調用本地的安卓代碼展示一個Dialog而不是使用JavaScript的alter()方法。通過addJavascriptInterface()方法創建接口。
示例:
定義一個“接口”類
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
在addJavascriptInterface方法中創建接口
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
在HTML的JavaScript中調用WebView顯示toast消息,
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
注意:
1 addJavascriptInterface方法中要綁定的Java對象及方法運行在另外的線程中,而不是運行在構造他的線程中。
2 使用addJavascriptInterface將會使javaScript可以操控安卓本地代碼。因此有可能導致安全性問題,請確保所有HTML代碼都是你所知道的。
3 如果targetSdkVersion是17或者更高(android 4.2以上),必須使用 @JavascriptInterface 註解,才能讓網頁訪問到本地代碼。
2.3 webview頁面處理
當用戶點擊webview中的網頁鏈接的時候,安卓系統默認會啓動一個新的應用專門成立url的跳轉。如果希望點擊鏈接繼續在當前webview中響應,而不是新開Android的系統browser中響應該鏈接,必須覆蓋 WebView的WebViewClient對象. 並重寫shouldOverrideUrlLoading方法。
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient.(new WebViewClient();
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (Uri.parse(url).getHost().equals("www.example.com")) {
// This is my web site, so do not override; let my WebView load the page
return false;
}
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}
2.4 webview的頁面導航處理
當webview的url進行跳轉的時候,自動回記錄進入歷史界面,可以使用goBack()方法和goForward()方法,進行返回和前進。
webview的canGoBack方法將會判斷歷史記錄中是否還有頁面,如果還有上一級頁面,將會返回true。
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
3 webview在項目中使用
如果還需要了解更多,推薦4 參考鏈接中的深入講解Webview(上,下)。
這裏接着介紹WebView在我項目中的使用。
3.1 需求是什麼?
當然在我項目中,最開始想做的一個體育新聞資訊,但是苦於自己沒有服務器,所以一開始都是模擬的數據。網上的開源api也是將所有新聞數據糅合在一起的,怎麼分開呢?比如nba,英超,歐冠,各種不同的新聞數據在哪裏獲取呢?作爲一個體育愛好者,經常會去的虎撲體育,然後找到了手機版的 虎撲體育。這不就是我想要的體育新聞數據嘛,O(∩_∩)O哈哈~。
但是我不想要這個頭部和底部呢 ,接下來分析怎麼處理,很簡單的實現。
3.2 效果怎麼樣?
看看運行效果,還是有模有樣的
3.3 怎麼做?
主要就是進行了新聞網頁的展示,並且去掉了頭部和底部。
public class WebViewFragment extends AbsTitleFragment {
......
R.layout.fragment_web_view;
......
@Override
protected void initViewsAndEvents(View rootView) {
mWebView.setVisibility(View.INVISIBLE);
toggleShowLoading(true, "loading");
setWebViewOption(mWebView);
if (getFragmentUrl() != null) {
mWebView.loadUrl(getFragmentUrl());
}
}
private void setWebViewOption(WebView webview) {
......
//設置是否支持運行JavaScript,僅在需要時打開
webview.getSettings().setJavaScriptEnabled(true);
......
//設置WebViewClient
webview.setWebViewClient(new MyWebViewClient());
webview.setWebChromeClient(new MyWebChromeClient());
}
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// view.loadUrl(url);
Intent intent = new Intent(mContext, WebViewActivity.class);
intent.putExtra(WebViewActivity.WEB_VIEW_URL, url);
startActivity(intent);
return true;
}
......
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
toggleShowLoading(false, "");
if (view.getVisibility() == View.INVISIBLE) {
view.setVisibility(View.VISIBLE);
}
}
......
}
private class MyWebChromeClient extends WebChromeClient {
......
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress > 25) {
injectJS(view);
}
super.onProgressChanged(view, newProgress);
}
}
private void injectJS(WebView webview) {
webview.loadUrl("javascript:(function() " +
"{ " +
"document.getElementsByClassName('m-top-bar')[0].style.display='none'; " +
"document.getElementsByClassName('m-footer')[0].style.display='none';" +
"document.getElementsByClassName('m-page')[0].style.display='none';" +
"})()");
}
}
可以看到WebView的初始化在setWebViewOption方法中進行。其中需要關注的有下面三行代碼
上面在WebSetting方法中WebViewClient的初始化,這裏主要是點擊新聞進行頁面跳轉的處理。
webview的返回鍵必須做處理,如果當前webview支持返回(不是點進來的第一個webview,而是再次跳轉的),則返回。如果不支持返回(第一個webview界面),則finish當前的頁面。
初始化WebView的時候也進行了WebChromeClient的初始化。其中主要是在當進度超過百分之25的時候注入了一段javaScript代碼。通過javascript代碼去掉了當前網頁的頭部和底部。
3.4 爲什麼這麼做?
上面就是通過對網頁信息注入js的形式,隱藏了相應的屬性。
如圖,去掉標題欄,在網頁中通過F12打開開發者工具,發現頂部欄的class的名字是m-top-bar,所以通過注入腳本的時候直接調用了這個class並且將display置爲none。對這方面不瞭解的可以學習一下Html5相關的知識。
至於爲什麼是在進度條進行25之後進行注入,這裏主要是在界面加載完成後再進行注入js就會有一定的卡頓閃屏現象。可以自己實踐一下。
本篇文章項目github地址:MVPCommon
注意:由於項目構建的需要,關於webview在本項目中利用js注入實現網頁列表的效果將在本項目中移除。(2016.7)
4 參考鏈接
Web Apps(官網)
->1 Supporting Different Screens from Web Apps(官網)
->2 Building Web Apps in WebView(官網)
->3 Migrating to WebView in Android 4.4(官網)
->4 Debugging Web Apps(官網)
->5 Best Practices for Web Apps(官網)