Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android開發使用WebView實戰技巧

Android開發使用WebView實戰技巧

編輯:關於Android編程

 

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

 

獲取網頁的Title信息

我們在打開某些應用的時候,例如今日頭條新聞客戶端等,有些頁面是使用WebView加載的,然而經常在界面的頂端會有標題欄,而且標題欄的內容不是我們自己在程序中寫死的,而是動態從網頁中獲取的,那麼我們怎麼獲取呢?大家都知道,在Html中,一個完整的網頁中必然會包含

標簽,標簽之間就是標題的內容,so我們只需要將Html中的title標簽中的內容獲取到就可以了。要獲取Title內容就必須設置WebView的setWebChromeClient(WebChromeClient client)方法,傳遞一個WebChromeClient 對象並且重寫其下的shouldOverrideUrlLoading(WebView view, String url)方法,該方法中回調了title就是 標簽間內容。例如:

 

...
mWebView = (WebView) findViewById(R.id.webview);
//開啟JavaScript支持
mWebView.getSettings().setJavaScriptEnabled(true);
//加載網頁
mWebView.loadUrl(http://www.baidu.com);
//強制在webview打開網頁,防止使用系統默認的浏覽器打開網頁
mWebView.setWebViewClient(new WebViewClient() {

	@Override
	public boolean shouldOverrideUrlLoading(WebView view, String url) {
		view.loadUrl(url);
		return super.shouldOverrideUrlLoading(view, url);
	}

});
mWebView.setWebChromeClient(new WebChromeClient() {

	@Override
	public void onReceivedTitle(WebView view, String title) {
		//onReceivedTitle可以回調網頁的title
		tv_title.setText(title);
		super.onReceivedTitle(view, title);
	}

});
...
\

 

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

用WebView下載文件

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

 

public class DownloadActivity extends Activity {

	private WebView mWebView;

	@Override
	protected 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() {
			@Override
			public boolean shouldOverrideUrlLoading(WebView view, String url) {
				view.loadUrl(url);
				return super.shouldOverrideUrlLoading(view, url);
			}
		});
		// 監聽下載
		mWebView.setDownloadListener(new DownloadListener() {

			@Override
			public 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;
		}

		@Override
		public 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() {
	...	
	@Override
	public 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同步cookie

cookie是什麼呢?這裡需要一些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) {
			// 同步Cookie
			CookieSyncManager.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);
		};
	};

	@Override
	protected 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;
		}

		@Override
		public void run() {
			//使用httpClient向服務器發送POST請求
			HttpClient client = new DefaultHttpClient();
			HttpPost post = new HttpPost(url);
			List list = new ArrayList();
			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 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;

	@Override
	protected 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() {
			@Override
			public 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代碼如下:

 

 



Java與JS回調

callJava:

<script type=text/javascript> function call(){ js.callJS(); } </script>此時寫的代碼在測試階段沒有問題,然後當混淆打包之後,會出現調用JS失效的可能,解決辦法:在混淆配置文件proguard.cfg中忽略WebHost裡面的方法

 

 

-keep public class com.example.webview_02.WebHost{
	public 
}

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved