騰訊的x5開(kāi)源庫(kù)的優(yōu)勢(shì):提高webView開(kāi)發(fā)效率套媚,大概要節(jié)約你百分之六十的時(shí)間成本。該案例支持處理js的交互邏輯且無(wú)耦合逝段、同時(shí)暴露進(jìn)度條加載進(jìn)度私股、可以監(jiān)聽(tīng)異常error狀態(tài)、支持視頻播放并且可以全頻冤留、支持加載word碧囊,xls,ppt纤怒,pdf糯而,txt等文件文檔、發(fā)短信泊窘、打電話熄驼、發(fā)郵件像寒、打開(kāi)文件操作上傳圖片、喚起原生App瓜贾、x5庫(kù)為最新版本诺祸,功能強(qiáng)大。
那么我們就來(lái)使用一下吧
導(dǎo)入依賴庫(kù)
implementation 'cn.yc:WebViewLib:1.1.2'
最簡(jiǎn)單使用
- 項(xiàng)目初始化
X5WebUtils.init(this);
- 最普通使用祭芦,需要自己做手動(dòng)設(shè)置setting相關(guān)屬性
<BridgeWebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarSize="3dp" />
- 也可以使用X5WebView筷笨,已經(jīng)做了常見(jiàn)的setting屬性設(shè)置
<X5WebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarSize="3dp" />
- 如果想有帶進(jìn)度的,可以使用ProgressWebView可以使用ProgressWebView
<ProgressWebView
android:id="@+id/web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbarSize="3dp" />
常用api
- 關(guān)于web的接口回調(diào)龟劲,包括常見(jiàn)狀態(tài)頁(yè)面切換胃夏,進(jìn)度條變化等監(jiān)聽(tīng)處理
mWebView.getX5WebChromeClient().setWebListener(interWebListener);
private InterWebListener interWebListener = new InterWebListener() {
@Override
public void hindProgressBar() {
pb.setVisibility(View.GONE);
}
@Override
public void showErrorView() {
//設(shè)置自定義異常錯(cuò)誤頁(yè)面
}
@Override
public void startProgress(int newProgress) {
pb.setProgress(newProgress);
}
};
具體的X5WebView的用法(帶進(jìn)度條)
public class Two_Activity extends AppCompatActivity {
private X5WebView mXView;
private ProgressBar mPb;
private QbSdk.PreInitCallback cb;
private static final String StringURL ="https://www.baidu.com/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_two_);
initView();
}
private void initView() {
mXView = (X5WebView) findViewById(R.id.x_view);
mXView.getX5WebChromeClient().setWebListener(interWebListener);
mPb = (ProgressBar) findViewById(R.id.pb);
initLoad();
}
private void initLoad() {
cb = new QbSdk.PreInitCallback() {
@Override
public void onCoreInitFinished() {
}
@Override
public void onViewInitFinished(boolean b) {
//x5內(nèi)核初始化完成的回調(diào),為true表示x5內(nèi)核加載成功昌跌,否則表示x5內(nèi)核加載失敗构订,會(huì)自動(dòng)切換到系統(tǒng)內(nèi)核。
Log.e("tag", " onViewInitFinished is " + b);
}
};
//x5內(nèi)核初始化接口
QbSdk.initX5Environment(getApplicationContext(), cb);
mXView.loadUrl(StringURL);
}
private InterWebListener interWebListener = new InterWebListener() {
@Override
public void hindProgressBar() {
mPb.setVisibility(View.GONE);
}
@Override
public void showErrorView() {
//設(shè)置自定義異常錯(cuò)誤頁(yè)面
Toast.makeText(Two_Activity.this, "未知錯(cuò)誤", Toast.LENGTH_SHORT).show();
}
@Override
public void startProgress(int newProgress) {
mPb.setProgress(newProgress);
}
};
}
- 關(guān)于視頻播放的時(shí)候避矢,web的接口回調(diào)悼瘾,主要是視頻相關(guān)回調(diào),比如全頻审胸,取消全頻亥宿,隱藏和現(xiàn)實(shí)webView
x5WebChromeClient = x5WebView.getX5WebChromeClient();
x5WebChromeClient.setVideoWebListener(new VideoWebListener() {
@Override
public void showVideoFullView() {
//視頻全頻播放時(shí)監(jiān)聽(tīng)
}
@Override
public void hindVideoFullView() {
//隱藏全頻播放,也就是正常播放視頻
}
@Override
public void showWebView() {
//顯示webView
}
@Override
public void hindWebView() {
//隱藏webView
}
});
使用建議
- 優(yōu)化一下相關(guān)的操作 關(guān)于設(shè)置js支持的屬性
@Override
public void onResume() {
super.onResume();
if (mWebView != null) {
mWebView.getSettings().setJavaScriptEnabled(true);
}
}
@Override
protected void onStop() {
super.onStop();
if (mWebView != null) {
mWebView.getSettings().setJavaScriptEnabled(false);
}
}
關(guān)于destroy銷毀邏輯
@Override
protected void onDestroy() {
try {
if (webView != null) {
webView.stopLoading();
webView.destroy();
webView = null;
}
} catch (Exception e) {
Log.e("X5WebViewActivity", e.getMessage());
}
super.onDestroy();
}
js調(diào)用(如何使用項(xiàng)目js調(diào)用)
- 代碼如下所示砂沛,下面中的jsname代表的是js這邊提供給客戶端的方法名稱
mWebView.registerHandler("jsname", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
}
});
- 如何回調(diào)數(shù)據(jù)給web那邊
function.onCallBack("回調(diào)數(shù)據(jù)");
js的調(diào)用時(shí)機(jī)分析
- onPageFinished()或者onPageStarted()方法中注入js代碼
做過(guò)WebView開(kāi)發(fā)烫扼,并且需要和js交互,大部分都會(huì)認(rèn)為js在WebViewClient.onPageFinished()方法中注入最合適碍庵,此時(shí)dom樹(shù)已經(jīng)構(gòu)建完成映企,頁(yè)面已經(jīng)完全展現(xiàn)出來(lái)。但如果做過(guò)頁(yè)面加載速度的測(cè)試静浴,會(huì)發(fā)現(xiàn)WebViewClient.onPageFinished()方法通常需要等待很久才會(huì)回調(diào)(首次加載通常超過(guò)3s)堰氓,這是因?yàn)閃ebView需要加載完一個(gè)網(wǎng)頁(yè)里主文檔和所有的資源才會(huì)回調(diào)這個(gè)方法。
能不能在WebViewClient.onPageStarted()中注入呢苹享?答案是不確定双絮。經(jīng)過(guò)測(cè)試,有些機(jī)型可以得问,有些機(jī)型不行囤攀。在WebViewClient.onPageStarted()中注入還有一個(gè)致命的問(wèn)題——這個(gè)方法可能會(huì)回調(diào)多次,會(huì)造成js代碼的多次注入宫纬。
從7.0開(kāi)始焚挠,WebView加載js方式發(fā)生了一些小改變,官方建議把js注入的時(shí)機(jī)放在頁(yè)面開(kāi)始加載之后漓骚。
WebViewClient.onProgressChanged()方法中注入js代碼
WebViewClient.onProgressChanged()這個(gè)方法在dom樹(shù)渲染的過(guò)程中會(huì)回調(diào)多次蝌衔,每次都會(huì)告訴我們當(dāng)前加載的進(jìn)度榛泛。
在這個(gè)方法中,可以給WebView自定義進(jìn)度條胚委,類似微信加載網(wǎng)頁(yè)時(shí)的那種進(jìn)度條
如果在此方法中注入js代碼,則需要避免重復(fù)注入叉信,需要增強(qiáng)邏輯亩冬。可以定義一個(gè)boolean值變量控制注入時(shí)機(jī)
那么有人會(huì)問(wèn)硼身,加載到多少才需要處理js注入邏輯呢硅急?
正是因?yàn)檫@個(gè)原因,頁(yè)面的進(jìn)度加載到80%的時(shí)候佳遂,實(shí)際上dom樹(shù)已經(jīng)渲染得差不多了营袜,表明WebView已經(jīng)解析了標(biāo)簽,這時(shí)候注入一定是成功的丑罪。在WebViewClient.onProgressChanged()實(shí)現(xiàn)js注入有幾個(gè)需要注意的地方:
1 上文提到的多次注入控制荚板,使用了boolean值變量控制
2 重新加載一個(gè)URL之前,需要重置boolean值變量吩屹,讓重新加載后的頁(yè)面再次注入js
3 如果做過(guò)本地js跪另,css等緩存,則先判斷本地是否存在煤搜,若存在則加載本地免绿,否則加載網(wǎng)絡(luò)js
4 注入的進(jìn)度閾值可以自由定制,理論上10%-100%都是合理的擦盾,不過(guò)建議使用了75%到90%之間可以嘲驾。
問(wèn)題反饋
視頻播放寬度超過(guò)屏幕
- 視頻播放寬度比webView設(shè)置的寬度大,超過(guò)屏幕:這個(gè)時(shí)候可以設(shè)置ws.setLoadWithOverviewMode(false);
x5加載office資源
- 關(guān)于加載word迹卢,pdf辽故,xls等文檔文件注意事項(xiàng):Tbs不支持加載網(wǎng)絡(luò)的文件,需要先把文件下載到本地腐碱,然后再加載出來(lái)
- 還有一點(diǎn)要注意榕暇,在onDestroy方法中調(diào)用此方法mTbsReaderView.onStop(),否則第二次打開(kāi)無(wú)法瀏覽喻杈。更多可以看FileReaderView類代碼彤枢!
WebView播放視頻問(wèn)題
1、此次的方案用到WebView筒饰,而且其中會(huì)有視頻嵌套缴啡,在默認(rèn)的WebView中直接播放視頻會(huì)有問(wèn)題, 而且不同的SDK版本情況還不一樣瓷们,網(wǎng)上搜索了下解決方案业栅,在此記錄下.
webView.getSettings.setPluginState(PluginState.ON);webView.setWebChromeClient(new WebChromeClient());
2秒咐、然后在webView的Activity配置里面加上: android:hardwareAccelerated="true"
3、以上可以正常播放視頻了碘裕,但是webview的頁(yè)面都finish了居然還能聽(tīng) 到視頻播放的聲音携取, 于是又查了下發(fā)現(xiàn)webview的onResume方法可以繼續(xù)播放,onPause可以暫停播放帮孔, 但是這兩個(gè)方法都是在Added in API level 11添加的雷滋,所以需要用反射來(lái)完成。
4文兢、停止播放:在頁(yè)面的onPause方法中使用:webView.getClass().getMethod("onPause").invoke(webView, (Object[])null);
5晤斩、繼續(xù)播放:在頁(yè)面的onResume方法中使用:webView.getClass().getMethod("onResume").invoke(webView,(Object[])null);這樣就可以控制視頻的暫停和繼續(xù)播放了。
無(wú)法獲取webView的正確高度
- 偶發(fā)情況姆坚,獲取不到webView的內(nèi)容高度
其中htmlString是一個(gè)HTML格式的字符串澳泵。
WebView view = new WebView(context);
view.loadData(htmlString, "text/html", "utf-8");
view.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.d("2", view.getContentheight() + "");
}
});
這是因?yàn)閛nPageFinished回調(diào)指的WebView已經(jīng)完成從網(wǎng)絡(luò)讀取的字節(jié)數(shù),這一點(diǎn)兼呵。在點(diǎn)onPageFinished被激發(fā)的頁(yè)面可能還沒(méi)有被解析兔辅。
第一種解決辦法:提供onPageFinished()一些延遲
webView.setWebViewClient(new WebViewClient() {
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
int contentHeight = webView.getContentHeight();
int viewHeight = webView.getHeight();
}
}, 500);
}
});
- 第二種解決辦法:使用js獲取內(nèi)容高度,具體可以看這篇文章:http://www.reibang.com/p/ad22b2649fba
WebView硬件加速導(dǎo)致頁(yè)面渲染閃爍
4.0以上的系統(tǒng)我們開(kāi)啟硬件加速后击喂,WebView渲染頁(yè)面更加快速幢妄,拖動(dòng)也更加順滑。但有個(gè)副作用就是茫负,當(dāng)WebView視圖被整體遮住一塊蕉鸳,然后突然恢復(fù)時(shí)(比如使用SlideMenu將WebView從側(cè)邊滑出來(lái)時(shí)),這個(gè)過(guò)渡期會(huì)出現(xiàn)白塊同時(shí)界面閃爍忍法。解決這個(gè)問(wèn)題的方法是在過(guò)渡期前將WebView的硬件加速臨時(shí)關(guān)閉潮尝,過(guò)渡期后再開(kāi)啟
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}