2017年Android5.0主流机型webview的兼容性出现大问题导致很多公司app都不使用h5播放视频,关于谷歌自带的webview有各种兼容问题,最典型的的就是视频全屏onShowCustomView经常会点击不回调,可能是谷歌推崇原生的app不想让html5的简单高效占领了app市场,就导致webview存在很多坑,而且看了网上很多博文的demo都会出现或多或少的不兼容。
如何实现一个完美的webview,就需要我们自己来添加webview的底层库文件,而不使用谷歌自带的,这样就可以全方位兼容webview,这里要实现微信那样的webview全部兼容效果.并且兼容Android 7.0系统。
腾讯浏览服务-首页 http://x5.tencent.com/tbs/sdk.htm 这个是有腾讯开发出来的sdk,微信上朋友圈就经常看的到这个效果
先上项目源码GitHub上:https://github.com/lshAndroid/WebviewTBS/tree/master
--------------------------------------------------------------------------------------------
开发文档:
下载 SDK jar 包放到工程的libs目录下,将源码和XML里的系统包和类替换为SDK里的包和类
需要注意的是:
1)请不要在代码里使用下述写法:
import android.*;
import android.webkit.*;
import android.webkit.WebStorage.*;
import android.net.*;
import android.net.http.*;
2)除了源码里需要把相关的包名和类名进行替换,布局xml里的声明也需要替换,例如:
android:id="@+id/webview_wechat" android:layout_width="fill_parent" android:layout_height="fill_parent" android:paddingLeft="5dp" android:paddingRight="5dp" />
为了确保替换的完整,可以使用脚本checkqbsdk.sh 点击下载 进行扫描,windows 上使用TBSSdk接入扫描工具.exe 点击下载 进行扫描。脚本放在所有源码的顶级目录下运行即可。后续的版本
布前尽量都运行一遍扫描,以免上次扫描后新提交的代码有未替换的情况发生。替换不完全时,可能发生的问题是关于cookie的身份错误、类转换时的crash等。cookie问题产生的原理是:一段代码把cookie塞给了系统内核,
另外一段代码尝试从x5的内核里读取cookie就失败了。类转换的错误产生的原理是:比如xml里指定的是系统的webview,java的代码里把它当作x5的webview使用。
AndroidManifest.xml里加入权限声明:
适配修改:
1. App 首次就可以加载 x5 内核
App 在启动后(例如在 Application 的 onCreate 中)立刻调用 QbSdk 的预加载接口 initX5Environment ,可参考接入示例,第一个参数传入 context,第二个参数传入 callback,不需要 callback 的可以传入 null,initX5Environment 内部会创建一个线程向后台查询当前可用内核版本号,这个函数内是异步执行所以不会阻塞 App 主线程,这个函数内是轻量级执行所以对 App 启动性能没有影响,当 App 后续创建 webview 时就可以首次加载 x5 内核了
2. 目前,由于SDK WebView所提供的WebView类,是对系统WebView的聚合包装,所以:获取系统内核的WebView或者 x5内核的WebView的宽高
android.webkit.WebView webView = new android.webkit.WebView(this);
int width = webView.getWidth();
需要采用下面的方式进行
com.tencent.smtt.sdk.WebView webView = new com.tencent.smtt.sdk.WebView(this);
int width = webView.getView().getWidth();
优化异常上报:
对于成熟的产品,都有自己的异常上报机制。当x5内核发生异常时,我们希望拿到x5内核的相关信息,以方便bug定位。请将WebView.getTbsCoreVersion()函数返回的内核版本信息、WebView.getTbsSDKVersion()函数返回的浏览器SDK版本信息、WebView.getCrashExtraMessage()函数返回的crash线索信息携带进异常上报的附加信息里。如果使用的是腾讯的RDM服务,代码添加到getCrashExtraMessage()函数里即可。
调整cookie的使用:
com.tencent.smtt.sdk.CookieManager和com.tencent.smtt.sdk.CookieSyncManager的相关接口的调用,在接入SDK后,需要放到创建X5的WebView之后(也就是X5内核加载完成)进行;否则,cookie的相关操作只能影响系统内核。
兼容视频播放:
1)享受页面视频的完整播放体验需要做如下声明:
页面的Activity需要声明android:configChanges="orientation|screenSize|keyboardHidden"
2)视频为了避免闪屏和透明问题,需要如下设置
a)网页中的视频,上屏幕的时候,可能出现闪烁的情况,需要如下设置:Activity在onCreate时需要设置:
getWindow().setFormat(PixelFormat.TRANSLUCENT);(这个对宿主没什么影响,建议声明)
b)在非硬绘手机和声明需要controller的网页上,视频切换全屏和全屏切换回页面内会出现视频窗口透明问题,需要如下设置
声明当前
特别说明:这个视各app情况所需,不强制需求,如果声明了,对体验更有利
c)以下接口禁止(直接或反射)调用,避免视频画面无法显示:
webview.setLayerType()
webview.setDrawingCacheEnabled(true);
输入法设置
避免输入法界面弹出后遮挡输入光标的问题
方法一:在AndroidManifest.xml中设置
android:windowSoftInputMode="stateHidden|adjustResize"
方法二:在代码中动态设置:
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
public class APIWebviewTBS { //二次封装tbs类,升级直接更换该类的方法\
private static APIWebviewTBS mAPIWebviewTBS;
public static APIWebviewTBS getAPIWebview() {
if (mAPIWebviewTBS == null) {
synchronized (APIWebviewTBS.class) {
if (mAPIWebviewTBS == null) {
mAPIWebviewTBS = new APIWebviewTBS();
}
}
}
return mAPIWebviewTBS;
}
public void initTbs(Context context) {//第一步:application的方法
//搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
//TbsDownloader.needDownload(getApplicationContext(), false);
QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
@Override
public void onViewInitFinished(boolean arg0) {
// TODO Auto-generated method stub
Log.e("app", " onViewInitFinished is " + arg0);
}
@Override
public void onCoreInitFinished() {
// TODO Auto-generated method stub
}
};
QbSdk.setTbsListener(new TbsListener() {
@Override
public void onDownloadFinish(int i) {
Log.d("app","onDownloadFinish");
}
@Override
public void onInstallFinish(int i) {
Log.d("app","onInstallFinish");
}
@Override
public void onDownloadProgress(int i) {
Log.d("app","onDownloadProgress:"+i);
}
});
// QbSdk.initX5Environment(getApplicationContext(), cb);
QbSdk.initX5Environment(context,cb); //二次封装更换
}
public void initTBSActivity(Activity ac){ //二次封装
if (ac!=null){
ac.getWindow().setFormat(PixelFormat.TRANSLUCENT);
ac.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
}
}
}