最近團(tuán)隊有需求將一個移動端網(wǎng)站打包成Android App实抡,最初嘗試過使用一些在線打包工具阁簸,但打包出來即難看又難用畔柔,所以還是擼起袖子自己干吧。需求無非是增加幾個Tab欄捍掺,接入微博微信分享等社交功能撼短,再用webview把網(wǎng)頁加載進(jìn)來,花了一點時間完成了挺勿,對常用的一些知識點做個總結(jié)曲横。
webview的一些細(xì)節(jié)
處理頁面導(dǎo)航
一般來說,在webview中點擊一個鏈接之后不瓶,Android會打開一個能處理URL事件的APP禾嫉,例如你默認(rèn)的瀏覽器,如果我們想要自己去處理webview中網(wǎng)頁的前進(jìn)后退甚至更多的事情蚊丐,就可以利用WebviewClient.
WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient());
竟然敢叫Native App熙参,我們自然就不會只有一個頁面,所以我們需要在用戶點擊某些鏈接時跳轉(zhuǎn)到新的Activity麦备,以及在頁面開始加載時顯示加載動畫孽椰,頁面結(jié)束加載時讓動畫結(jié)束,此時我們可以重載WebViewClient中的方法泥兰。
private WebViewClient mClient = new WebViewClient() {
public void onPageStarted(WebView view, String url, Bitmap favicon) {
mRefreshLayout.setRefreshing(true);
}
@Override
public void onPageFinished(WebView view, String url) {
if (mRefreshLayout.isRefreshing()) {
mRefreshLayout.setRefreshing(false);
}
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Intent intent = new Intent(getActivity(), DetailsActivity.class);
intent.putExtra(AppUtil.KEY_URL, url);
startActivity(intent);
return true;
}
};
}
除此之外弄屡,當(dāng)然可以通過重載webviewclient做更多的事情,如自定義網(wǎng)頁出錯界面等等鞋诗。
獲取頁面標(biāo)題
我們通嘲蚪荩可以通過實現(xiàn)WebChromeClient中的接口去獲取與顯示網(wǎng)頁標(biāo)題:
mWebView.setWebChromeClient(new WebChromeClient() {
public void onReceivedTitle(WebView view, String title){
mTitle.setText(title);
}
});
但是當(dāng)你在一個webview中有不同鏈接跳轉(zhuǎn),再通過webview.goback()返回的時候削彬,標(biāo)題并不會更新全庸,其實我們可以在WebviewClient中實現(xiàn)onPageFinish接口時通過view.getTitle去獲取標(biāo)題,此時goback時也是能獲取到標(biāo)題更新的融痛。
UserAgent
網(wǎng)頁的移動端通常有自己的導(dǎo)航欄設(shè)計壶笼,我們在native中增加了導(dǎo)航欄,如果此時繼續(xù)讓網(wǎng)頁的導(dǎo)航欄加載出來雁刷,界面就會出現(xiàn)兩個導(dǎo)航欄覆劈,所以我們需要告訴網(wǎng)頁,訪問并非來源于一個真正的瀏覽器沛励,而是一個App责语,當(dāng)網(wǎng)頁識別到該訪問時,即將自己的導(dǎo)航欄隱藏掉目派。我們可以通過下面這段代碼獲取并定制專屬App的UserAgent.
WebSettings webSettings = mWebView.getSettings();
String userAgent = webSettings.getUserAgentString();
userAgent = userAgent.concat(" app和網(wǎng)頁約定的字串");
webSettings.setUserAgentString(userAgent);
緩存
大多數(shù)需要訪問網(wǎng)頁的App坤候,假設(shè)你已經(jīng)成功訪問了網(wǎng)頁,那么下一次你斷掉網(wǎng)絡(luò)之后再訪問企蹭,還是可以看到上次訪問的頁面白筹,所以我們可以在有網(wǎng)絡(luò)時去獲取新數(shù)據(jù)智末,而沒有網(wǎng)絡(luò)時即從webview的緩存中去加載數(shù)據(jù)。webview有四種緩存模式徒河,根據(jù)需要靈活使用系馆。
if (AppUtil.isNetworkConnected(getActivity())) {
webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
} else {
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
}
js交互
有時候我們需要在客戶端與js代碼做交互,在我的項目中虚青,加載網(wǎng)頁時它呀,執(zhí)行一段Js代碼,返回用戶是否登錄的信息棒厘,在這里就簡單的使用js讓客戶端彈toast作演示。
首先下隧,定義一個類奢人,用于讓js代碼調(diào)用:
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();
}
}
調(diào)用下面這段代碼,將WebAppInterface與webview綁定起來:
WebView webView = (WebView) findViewById(R.id.webview);
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
至此淆院,js代碼就可以和客戶端通信了何乎。
<input type="button" value="Say hello" onClick="showAndroidToast('Hello Android!')" />
<script type="text/javascript">
function showAndroidToast(toast) {
Android.showToast(toast);
}
</script>
上面這段代碼,是寫在網(wǎng)頁端的土辩,如果我們想客戶端主動插入js代碼也是可以的支救,非常簡單:
String js = "Android.showToast(\"Hello Android\")"
webview.loadurl(“javascript:”+js);
代碼混淆
興高采烈的打開混淆準(zhǔn)備發(fā)布應(yīng)用的時候發(fā)現(xiàn),所有的js調(diào)用不生效了拷淘!打開proguard-rules.pro可以發(fā)現(xiàn)顯著的提示:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
所以各墨,我們必須將有webviwe和js交互的類作聲明,且必須使用完整的包名路徑:
-keepclassmembers class com.google.test.TestActivity {
public *;
}
同時4.2以上版本中我們需要對js調(diào)用接口作@javascriptinterface,聲明,為了聲明不丟失启涯,我們還需要加上:
-keepattributes *Annotation*
-keepattributes *JavascriptInterface*