Android開發使用WebView實戰技巧

來源:互聯網
上載者:User

標籤:webview   javascript   cookie   webview下載檔案   js調用混淆   

  轉載請註明出處:http://blog.csdn.net/allen315410/article/details/44619181      

        前段時間做項目的時候,在項目中用了WebView組件,遇到了一些問題,所以特地找來了一些資料,學習怎麼解決,現在將學習的內容整理成一篇部落格記錄在這裡,方便以後再次遇到時可以快速查看並且解決問題。我們知道,Android中WebView是一個大型的組件,其實WebView是整合了著名的瀏覽器引擎webkit的一個架構,主要是用來在Android應用中載入渲染網頁的。好了,這篇學習筆記之前,我也學習了Google的官方文檔,介紹WebView的基本用法,並且翻譯好了,地址是:http://blog.csdn.net/allen315410/article/details/44647171,請還沒用過WebView的同學,先查看一下這篇文章後,再看我下面的內容。


擷取網頁的Title資訊

我們在開啟某些應用的時候,例如今日頭條新聞用戶端等,有些頁面是使用WebView載入的,然而經常在介面的頂端會有標題列,而且標題列的內容不是我們自己在程式中寫死的,而是動態從網頁中擷取的,那麼我們怎麼擷取呢?大家都知道,在Html中,一個完整的網頁中必然會包含<title></title>標籤,標籤之間就是標題的內容,so我們只需要將Html中的title標籤中的內容擷取到就可以了。要擷取Title內容就必須設定WebView的setWebChromeClient(WebChromeClient client)方法,傳遞一個WebChromeClient 對象並且重寫其下的shouldOverrideUrlLoading(WebView view, String url)方法,該方法中回調了title就是<title></title>標籤間內容。例如:

...mWebView = (WebView) findViewById(R.id.webview);//開啟JavaScript支援mWebView.getSettings().setJavaScriptEnabled(true);//載入網頁mWebView.loadUrl("http://www.baidu.com");//強制在webview開啟網頁,防止使用系統預設的瀏覽器開啟網頁mWebView.setWebViewClient(new WebViewClient() {@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {view.loadUrl(url);return super.shouldOverrideUrlLoading(view, url);}});mWebView.setWebChromeClient(new WebChromeClient() {@Overridepublic void onReceivedTitle(WebView view, String title) {//onReceivedTitle可以回調網頁的titletv_title.setText(title);super.onReceivedTitle(view, title);}});...

如所示,webview中開啟了網頁,並且將title現在在了TextView標題上。

用WebView下載檔案

同樣的,當我們在使用瀏覽器的時候,很多時候會需要下載檔案,瀏覽器是個功能十分強大的應用,可以協助我們下載網上的檔案,那麼如果我們的應用中整合了WebView組件,其中渲染的網頁也有檔案可供下載時,我們該怎麼去做下載功能呢?同樣,既然瀏覽器功能那麼強大,我們的WebView組件也不差。下面我們看看WebView是怎樣下載檔案的。

public class DownloadActivity extends Activity {private WebView mWebView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_download);mWebView = (WebView) findViewById(R.id.webview);// 開啟JavaScript支援mWebView.getSettings().setJavaScriptEnabled(true);mWebView.loadUrl("http://img.mukewang.com/down/54eec5f10001b17600000000.zip");mWebView.setWebViewClient(new WebViewClient() {@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {view.loadUrl(url);return super.shouldOverrideUrlLoading(view, url);}});// 監聽下載mWebView.setDownloadListener(new DownloadListener() {@Overridepublic void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {System.out.println("url:" + url);if (url.endsWith(".zip")) {// 如果傳進來url包含.zip檔案,那麼就開啟下載線程System.out.println("download start...");new DownloadThread(url).start();}}});}/** * 執行下載的線程 */class DownloadThread extends Thread {private String mUrl;public DownloadThread(String url) {this.mUrl = url;}@Overridepublic void run() {try {URL httpUrl = new URL(mUrl);HttpURLConnection conn = (HttpURLConnection) httpUrl.openConnection();conn.setDoInput(true);conn.setDoOutput(true);conn.setConnectTimeout(5000);conn.setReadTimeout(5000);InputStream in = conn.getInputStream();FileOutputStream out = null;// 擷取下載路徑File downloadFile;File sdFile;if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {downloadFile = Environment.getExternalStorageDirectory();sdFile = new File(downloadFile, "download.zip");out = new FileOutputStream(sdFile);}byte[] b = new byte[8 * 1024];int len;while ((len = in.read(b)) != -1) {if (out != null) {out.write(b, 0, len);}}if (out != null) {out.close();}if (in != null) {in.close();}System.out.println("download success...");} catch (MalformedURLException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}}

其實特別簡單,WebView中已經給我們提供好一個實現下載的介面以及回調方法,這個介面就是android.webkit.DownloadListener,我們首先調用WebView的setDownloadListener(DownloadListener listener)方法,在方法參數中傳入DownloadListener對象,重寫其中的onDownloadStart方法,在這個方法中開啟下載功能的線程,讓線程協助我們去伺服器下載檔案。


WebView錯誤碼的處理

WebView錯誤碼處理是什麼意思呢?我們在使用Android裝置的時候,可能某些時候網路不好或者沒有網路,這時候裝置就訪問不到伺服器了,載入不了Html頁面。一般情況下,當我們的裝置無網路情況下載入一個Html時,會自行彈出Android預設的錯誤頁面,如:


好了,這就是Android系統中給我們預設的頁面了,是不是值得我們吐槽一下呢?同樣將這個頁面呈現給使用者也會被罵死的,那麼我們該怎麼處理這樣的情況呢?方式也很簡單,主要有2種方式實現,一是載入一個本地的Html頁面,告知網路異常,二是通過布局的方式自訂一個錯誤提示介面,載入到主介面。好了,上面的兩種實現方式都不是重點,我們不討論怎麼製作一個好看的Html Error頁面或者一個好看的XML布局。

監聽WebView載入出錯是在setWebViewClient()的傳遞WebViewClient對象下的onReceivedError()方法中完成處理的,下面是一個簡單的處理方式:

mWebView.setWebViewClient(new WebViewClient() {...@Overridepublic void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {//網路異常,WebView載入我們自訂的頁面super.onReceivedError(view, errorCode, description, failingUrl);view.loadUrl("file:///android_asset/error.html");}});
好了,上面代碼中做了簡單處理:重新載入本地的assets目錄的html靜態頁面。


WebView同步cookiecookie是什麼呢?這裡需要一些Java伺服器上面的知識了,簡單來說Cookie算是伺服器上一種緩衝機制了,例如我們在登入的時候第一次輸入了登入的使用者名稱和密碼,並且儲存了密碼,那麼下次我們再次開啟這個網頁的時候就會自動讀取cookie完成自動登入了。如果這個含有cookie的頁面使用WebView載入的話,該怎樣也能實現相同的功能呢?我們只有設定WebView與Cookie同步即可。

public class CookieTestActivity extends Activity {private WebView mWebView;private Handler mHandler = new Handler() {public void handleMessage(Message msg) {// 同步CookieCookieSyncManager.createInstance(CookieTestActivity.this);CookieManager cookieManager = CookieManager.getInstance();cookieManager.setAcceptCookie(true);cookieManager.setCookie("http://192.168.1.105:8080/webs", msg.obj.toString());CookieSyncManager.getInstance().sync();mWebView.loadUrl("http://192.168.1.105:8080/webs/index.jsp");};};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_download);mWebView = (WebView) findViewById(R.id.webview);// 開啟JavaScript支援mWebView.getSettings().setJavaScriptEnabled(true);String url = "http://192.168.1.105:8080/webs/login.jsp";new HttpCookie(mHandler, url).start();}/** * 訪問伺服器,讀取Cookie資訊 */class HttpCookie extends Thread {private Handler handler;private String url;public HttpCookie(Handler handler, String url) {this.handler = handler;this.url = url;}@Overridepublic void run() {//使用httpClient向伺服器發送POST請求HttpClient client = new DefaultHttpClient();HttpPost post = new HttpPost(url);List<NameValuePair> list = new ArrayList<NameValuePair>();list.add(new BasicNameValuePair("name", "zhangsan"));list.add(new BasicNameValuePair("age", "22"));try {post.setEntity(new UrlEncodedFormEntity(list));HttpResponse response = client.execute(post);if (response.getStatusLine().getStatusCode() == 200) {//訪問伺服器成功,從伺服器讀取Cookie資訊AbstractHttpClient absClient = (AbstractHttpClient) client;List<Cookie> cookies = absClient.getCookieStore().getCookies();for (Cookie cookie : cookies) {// 將Cookie發送到UI線程Log.d("TAG", "name=" + cookie.getName() + ",age=" + cookie.getValue());Message message = Message.obtain();message.obj = cookie;handler.sendMessage(message);return;}}} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}}}

好,通過上面的範例程式碼,我們很快就知道怎麼設定Cookie同步了,主要代碼是在Handler中的。


WebView與JS調用混淆問題

這個問題會經常遇到,當我們在Java中寫好了調用JS的代碼後,測試的時候完全正常的,然而我們在發布程式的時候,需要混淆打包,混淆打包之後的生存了我們的.apk檔案,將apk安裝到裝置上後,再次調用JS的時候,會發現調用方法失效了,這是一件讓人惱火的時候。這時候為瞭解決這個問題,我們需要對JS調用的相關代碼做一些保護,保護措施也非常簡單,只需要在混淆檔案中將JS調用的Java層代碼忽略掉就可以了。

這是Activity:

public class MainActivity extends Activity {private WebView mWebView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mWebView = (WebView) findViewById(R.id.webview);mWebView.loadUrl("file:///android_asset/index.html");mWebView.setWebViewClient(new WebViewClient() {@Overridepublic boolean shouldOverrideUrlLoading(WebView view, String url) {view.loadUrl("file:///android_asset/index.html");return true;}});mWebView.getSettings().setJavaScriptEnabled(true);mWebView.addJavascriptInterface(new WebHost(this), "js");}}
然後我們還要寫一個調用JS類:

public class WebHost {private Context mContext;public WebHost(Context context) {this.mContext = context;}public void callJS() {Toast.makeText(mContext, "call from js", Toast.LENGTH_SHORT).show();}}
JS代碼如下:

<html>  <title>    <head>Java與JS回調</head>  </title>  <body>    <p>    callJava:<input type="button" value="call from js" onclick="call()"/>   </p>   <script type="text/javascript">function call(){js.callJS();}  </script>  </body></html>
此時寫的代碼在測試階段沒有問題,然後當混淆打包之後,會出現調用JS失效的可能,解決辦法:在混淆設定檔proguard.cfg中忽略WebHost裡面的方法

-keep public class com.example.webview_02.WebHost{public <methods>}

Android開發使用WebView實戰技巧

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.