1、基礎(chǔ)用法
1)加載本地assert目錄下文件(error.html)
webcontent.loadUrl(" file:///android_asset/error.html ");
2)加載網(wǎng)絡(luò)url(http://www.csdn.com)
webcontent.loadUrl(" http://www.csdn.com ");
3)加載 String 類型html
String errorHtml = "<html><body><h1>Page not find!</h1></body></html>";
webcontent.loadData(errorHtml,"text/html", "UTF-8");
4)加載SD卡html:
webcontent.loadUrl(" content://com.android.htmlfileprovider/sdcard/kris.html ");
注意:
加載html代碼片段的時候解恰,水平方向適應(yīng)全屏效果不好
解決思路:將“代碼片段”補充為“完成的html代碼”(參考:https://blog.csdn.net/u011692041/article/details/51063540)
解決方法:
/**
* 將html片段拼接成完整的html代碼
* 優(yōu)點:為了更好的自適應(yīng)全屏顯示
*
* @param excerptHtml
* @return
*/
private String getCompleteHtml(String excerptHtml) {
? ? StringBuilder sb = new StringBuilder();
? ? String codeStart = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\"http://www.w3.org/TR/html4/loose.dtd\">" +
? ? ? ? ? ? ? ? "<html>" +
? ? ? ? ? ? ? ? "<head>" + "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover\">" +
? ? ? ? ? ? ? ? "<style>img{width:100% !important;}</style>" +
? ? ? ? ? ? ? ? "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=\"></head>" + "<body style='word-wrap:break-word;font-family:Arial;'>";
? ? ? ? String codeEnd = "</body></html>";
? ? return sb.append(codeStart).append(excerptHtml).append(codeEnd).toString();
}
2霉撵、webView與js通信
1) Android調(diào)用JS代碼
主要有兩種方法:
? ● 通過WebView的loadUrl()
// 調(diào)用javascript的callJS()方法
mWebView.loadUrl("javascript:callJS()");
但是這種不常用,因為它會自動刷新頁面而且沒有返回值帘撰,有點影響交互跑慕。
? ● 通過WebView的evaluateJavascript()
mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
? ? ? ? @Override
? ? ? ? public void onReceiveValue(String value) {
? ? ? ? ? ? //此處為 js 返回的結(jié)果
? ? ? ? }
? ? });
這種就比較全面了。調(diào)用方法并且獲取返回值摧找。
2) JS調(diào)用Android端代碼
主要有兩種方法:
? ● 通過WebView的addJavascriptInterface()進行對象映射
public class AndroidtoJs extends Object {
? ? // 定義JS需要調(diào)用的方法
? ? // 被JS調(diào)用的方法必須加入@JavascriptInterface注解
? ? @JavascriptInterface
? ? public void hello(String msg) {
? ? ? ? System.out.println("JS調(diào)用了Android的hello方法");
? ? }
}
mWebView.addJavascriptInterface(new AndroidtoJs(), "test");
//js中:
function callAndroid(){
? ? // 由于對象映射核行,所以調(diào)用test對象等于調(diào)用Android映射的對象
? ? test.hello("js調(diào)用了android中的hello方法");
}
這種方法雖然很好用,但是要注意的是4.2以后蹬耘,對于被調(diào)用的函數(shù)以@JavascriptInterface進行注解芝雪,否則容易出發(fā)漏洞,因為js方可以通過反射調(diào)用一些本地命令婆赠,很危險绵脯。
? ● 通過WebViewClient 的shouldOverrideUrlLoading ()方法回調(diào)攔截 url
這種方法是通過shouldOverrideUrlLoading回調(diào)去攔截url,然后進行解析休里,如果是之前約定好的協(xié)議蛆挫,就調(diào)用相應(yīng)的方法。
// 復(fù)寫WebViewClient類的shouldOverrideUrlLoading方法
mWebView.setWebViewClient(new WebViewClient() {
? ? ? ? @Override
? ? ? ? public boolean shouldOverrideUrlLoading(WebView view, String url) {
? Uri uri = Uri.parse(url);? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? // 如果url的協(xié)議 = 預(yù)先約定的 js 協(xié)議
? ? ? ? ? ? if ( uri.getScheme().equals("js")) {
? // 如果 authority? = 預(yù)先約定協(xié)議里的 webview妙黍,即代表都符合約定的協(xié)議
? ? ? ? ? ? if (uri.getAuthority().equals("webview")) {
? ? ? ? ? ? ? System.out.println("js調(diào)用了Android的方法");
? ? ? ? ? ? ? // 可以在協(xié)議上帶有參數(shù)并傳遞到Android上
? ? ? ? ? ? ? HashMap<String, String> params = new HashMap<>();
? ? ? ? ? ? ? Set<String> collection = uri.getQueryParameterNames();
? ? }
? ? ? ? ? ? return true;
? ? ? ? ? ? }
? ? ? ? ? ? return super.shouldOverrideUrlLoading(view, url);
? ? ? ? ? ? }
? ? ? ? }
? ? );
3悴侵、如何避免WebView內(nèi)存泄露
WebView的內(nèi)存泄露主要是因為在頁面銷毀后,WebView的資源無法馬上釋放所導(dǎo)致的∈眉蓿現(xiàn)在主流的是兩種方法:
1)不在xml布局中添加webview標簽可免,采用在代碼中new出來的方式,并在頁面銷毀的時候去釋放webview資源
//addview
private WeakReference<BaseWebActivity> webActivityReference = new WeakReference<BaseWebActivity>(this);
mWebView = new BridgeWebView(webActivityReference .get());
webview_container.addView(mWebView);
//銷毀
ViewParent parent = mWebView.getParent();
if (parent != null) {
? ? ((ViewGroup) parent).removeView(mWebView);
}
mWebView.stopLoading();
mWebView.getSettings().setJavaScriptEnabled(false);
mWebView.clearHistory();
mWebView.clearView();
mWebView.removeAllViews();
mWebView.destroy()做粤;
mWebView=null浇借;
2)另起一個進程加載webview,頁面銷毀后干掉這個進程怕品。但是這個方法的麻煩之處就在于進程間通信妇垢。
使用方法很簡單,xml文件中寫出進程名即可肉康,銷毀的時候調(diào)用System.exit(0)
<activity android:name=".WebActivity"
? android:process=":remoteweb"/>
System.exit(0)?
4砖顷、webView還有哪些可以優(yōu)化的地方
? ● 提前初始化或者使用全局WebView嫡纠。首次初始化WebView會比第二次初始化慢很多。初始化后逢享,即使WebView已釋放芯肤,但一些多WebView共用的全局服務(wù)/資源對想仍未釋放蹂空,而第二次初始化不需要生成膏燕,因此初始化變快。
? ● DNS采用和客戶端API相同的域名献丑,DNS解析也是耗時比較多的部分,所以用客戶端API相同的域名因為其DNS會被緩存光督,所以打開webView的時候就不會再耗時在DNS上了
? ● 對于JS的優(yōu)化阳距,盡量不要用偏重的框架,比如React结借。其次是高性能要求頁面還是需要后端渲染。最后就是app中的網(wǎng)頁框架要統(tǒng)一卒茬,這樣就可以對js進行緩存和復(fù)用船老。
這里有美團團隊的總結(jié)方案,如下:
? ● WebView初始化慢圃酵,可以在初始化同時先請求數(shù)據(jù)柳畔,讓后端和網(wǎng)絡(luò)不要閑著。
? ● 后端處理慢郭赐,可以讓服務(wù)器分trunk輸出薪韩,在后端計算的同時前端也加載網(wǎng)絡(luò)靜態(tài)資源。
? ● 腳本執(zhí)行慢捌锭,就讓腳本在最后運行俘陷,不阻塞頁面解析。
? ● 同時观谦,合理的預(yù)加載拉盾、預(yù)緩存可以讓加載速度的瓶頸更小。
? ● WebView初始化慢豁状,就隨時初始化好一個WebView待用捉偏。
? ● DNS和鏈接慢,想辦法復(fù)用客戶端使用的域名和鏈接泻红。
? ● 腳本執(zhí)行慢夭禽,可以把框架代碼拆分出來,在請求頁面之前就執(zhí)行好谊路。
5讹躯、webview常見問題