社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
大家都不知道原生的WebView 存在各种坑。各种适配问题。
最近在使用,总会出现DNS被拦截的情况。预览了各个大神的论坛与博客。
发现可以更改WebView内核。找到了比较火的两个。
分别是:腾讯X5内核 和 crosswalk
crosswalk : 据说很强大,但缺点就是会让你的APK包增大很多。(我还没试过,都是看大神们的博客说的)
大家可以参考这篇文章 如何轻松搞定Crosswalk之嵌入模式
相对crosswalk呢,腾讯X5 比较适合我目前的项目。至少包不会一下子给我 增大那么多
TBS腾讯浏览服务(点击跳转官网)
腾讯X5的好处我就不再说了,官网解释的肯定比我到位,我怎么做的吧。
第一步:那肯定是下载官方的SDK 包啦(腾讯浏览服务-SDK下载) 我这里下载的是上面这个
第二步:根据SDK 提供的jar包和so 包拷贝到自己的项目下。
(注意:我这里和官方提供的so,放的位置可能有点区别,这个就需要看的项目情况了)
注意:x5暂时不提供64位so文件,为了保证64位手机能正常加载x5内核,请参照如下链接修改相关配置
https://x5.tencent.com/tbs/technical.html#/detail/sdk/1/34cf1488-7dc2-41ca-a77f-0014112bcab7
官方的Demo ,so包是放在 srcmainjniLibs 下这个可以看一下官方包。就知道了
在Demo 中的build.gradle,中有说到 so 包的目录位置
第三步:接下来就开始被配置,初始化X5了,在APP的 Application 中 onCreate() 去初始化
private void initX5() {
QbSdk.setDownloadWithoutWifi(true);
//x5内核初始化接口//搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
QbSdk.initX5Environment(getApplicationContext(), new QbSdk.PreInitCallback() {
@Override
public void onViewInitFinished(boolean arg0) {
//x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
Log.d("app", " onViewInitFinished is " + arg0);
}
@Override
public void onCoreInitFinished() {
}
});
}
在清单文件中去添加
<!-- 腾讯X5内核初始化 -->
<service android:name="com.tencent.smtt.export.external.DexClassLoaderProviderService"
android:label="dexopt"
android:process=":dexopt" />
第四步 :继承 com.tencent.smtt.sdk.WebView 自定义 WebView (这里根据自己的情况定义)
public class SimpleWebView extends com.tencent.smtt.sdk.WebView {
public SimpleWebView(Context context) {
super(context);
init();
}
public SimpleWebView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SimpleWebView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@SuppressLint("SetJavaScriptEnabled")
private void init() {
WebSettings webSetting = this.getSettings();
webSetting.setJavaScriptEnabled(true);
webSetting.setJavaScriptCanOpenWindowsAutomatically(true);
webSetting.setAllowFileAccess(true);
webSetting.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
webSetting.setSupportZoom(true);
webSetting.setBuiltInZoomControls(true);
webSetting.setUseWideViewPort(true);
webSetting.setSupportMultipleWindows(true);
// webSetting.setLoadWithOverviewMode(true);
webSetting.setAppCacheEnabled(true);
// webSetting.setDatabaseEnabled(true);
webSetting.setDomStorageEnabled(true);
webSetting.setGeolocationEnabled(true);
webSetting.setAppCacheMaxSize(Long.MAX_VALUE);
// webSetting.setPageCacheCapacity(IX5WebSettings.DEFAULT_CACHE_CAPACITY);
webSetting.setPluginState(WebSettings.PluginState.ON_DEMAND);
// webSetting.setRenderPriority(WebSettings.RenderPriority.HIGH);
webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);
this.setWebViewClient(new SimpleWebViewClient());
this.setWebChromeClient(new WebChromeClient(){
//这里可以设置进度条。但我是用另外一种
@Override
public void onProgressChanged(WebView webView, int i) {
super.onProgressChanged(webView, i);
}
});
}
public static class SimpleWebViewClient extends com.tencent.smtt.sdk.WebViewClient {
private SimpleLoadingDialog loadingDialog;
@Override
public com.tencent.smtt.export.external.interfaces.WebResourceResponse shouldInterceptRequest(com.tencent.smtt.sdk.WebView webView, String url) {
//做广告拦截,ADFIlterTool 为广告拦截工具类
if (!ADFilterTool.hasAd(webView.getContext(),url)){
return super.shouldInterceptRequest(webView, url);
}else {
return new WebResourceResponse(null,null,null);
}
}
/**
* 防止加载网页时调起系统浏览器
*/
@Override
public boolean shouldOverrideUrlLoading(com.tencent.smtt.sdk.WebView webView, String url) {
webView.loadUrl(url);
return true;
}
//在开始的时候,开始loadingDialog
@Override
public void onPageStarted(com.tencent.smtt.sdk.WebView webView, String s, Bitmap bitmap) {
super.onPageStarted(webView, s, bitmap);
try{
loadingDialog = new SimpleLoadingDialog(webView.getContext(),true);
loadingDialog.show();
}catch (Exception e){}
}
//在页面加载结束的时候,关闭LoadingDialog
@Override
public void onPageFinished(com.tencent.smtt.sdk.WebView webView, String s) {
super.onPageFinished(webView, s);
try {
if (loadingDialog != null) {
loadingDialog.dismiss();
}
} catch (Exception e) {}
}
@Override
public void onReceivedError(com.tencent.smtt.sdk.WebView webView, com.tencent.smtt.export.external.interfaces.WebResourceRequest webResourceRequest, com.tencent.smtt.export.external.interfaces.WebResourceError webResourceError) {
super.onReceivedError(webView, webResourceRequest, webResourceError);
}
@Override
public void onReceivedSslError(com.tencent.smtt.sdk.WebView webView, com.tencent.smtt.export.external.interfaces.SslErrorHandler sslErrorHandler, com.tencent.smtt.export.external.interfaces.SslError sslError) {
sslErrorHandler.proceed();
}
}
}
接下来就是使用了,和我们原生的webView 没什么区别啦。
/**
* 初始化webView
*/
@SuppressLint("SetJavaScriptEnabled")
private void initDetailsH5() {
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new SimpleWebView.SimpleWebViewClient(){
@Override
public void onPageFinished(com.tencent.smtt.sdk.WebView webView, String url) {
super.onPageFinished(webView, url);
toolbarTitle.setText(webView.getTitle());//获取WebView 的标题,设置到toolbar中去
}
@Override
public boolean shouldOverrideUrlLoading(com.tencent.smtt.sdk.WebView webView, String url) {
if (url.contains("Activity/")){
...
}else if (url.contains("Share")){
...
}else {
webView.loadUrl(url);
}
return true;
}
});
}
/**
* 监听系统返回键,判断WebView是否有上一级,有的话就返回WebView的上一级
* 否则返回页面
*
* @param keyCode
* @param event
* @return
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (webView != null && webView.canGoBack()) {
webView.goBack();
return true;
} else {
return super.onKeyDown(keyCode, event);
}
}
return super.onKeyDown(keyCode, event);
}
第五步:这里也根据需要添加吧。就是广告拦截了。广告库加多了的话,可能就会影响性能了。
(我觉的这种做法存在很大的问题,如果建议直接使用Https。就可以避免这个问题)
public class ADFilterTool {
/**
* 屏蔽广告的NoAdWebViewClient类
*
* @param context
* @param url
* @return true 为广告链接,false 为正常连接
*/
public static boolean hasAd(Context context, String url) {
Resources res = context.getResources();
String[] adUrls = res.getStringArray(R.array.adBlockUrl);
for (String adUrl : adUrls) {
if (url.contains(adUrl)) {
return true;
}
}
return false;
}
}
在 res vlaues 目录下创建 AdUrlString.xml
(注:广告库部分摘取 Android Webview广告过滤的实现)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="adBlockUrl">
<item>ubmcmm.baidustatic.com</item>
<item>gss1.bdstatic.com/</item>
<item>cpro2.baidustatic.com</item>
<item>cpro.baidustatic.com</item>
<item>lianmeng.360.cn</item>
<item>nsclick.baidu.com</item>
<item>caclick.baidu.com/</item>
<item>jieaogd.com</item>
<item>publish-pic-cpu.baidu.com/</item>
<item>cpro.baidustatic.com/</item>
<item>hao61.net/</item>
<item>cpu.baidu.com/</item>
<item>pos.baidu.com</item>
<item>cbjs.baidu.com</item>
<item>cpro.baidu.com</item>
<item>images.sohu.com/cs/jsfile/js/c.js</item>
<item>union.sogou.com/</item>
<item>sogou.com/</item>
<item>5txs.cn/</item>
<item>liuzhi520.com/</item>
<item>yhzm.cc/</item>
<item>jieaogd.com</item>
<item>a.baidu.com</item>
<item>c.baidu.com</item>
<item>mlnbike.com</item>
<item>alipays://platformapi</item>
<item>alipay.com/</item>
<item>jieaogd.com</item>
<item>vipshop.com</item>
</string-array>
</resources>
接下来就是 CookieUtils ,同步WebView 的Cookie。为什么要同步Cookie ,我这就不介绍啦。
可以看一下我另外一篇文章,会有比较详细的Cookie同步。Android H5 交互Cookie 同步登录状态
最后温馨提醒一下,如果没有添加权限,注意加一下权限噢~
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 硬件加速对X5视频播放非常重要,建议开启 -->
<uses-permission android:name="android.permission.GET_TASKS" />
第六步:如果需要做适配兼容的需要配置以下配置
兼容视频播放:
1)享受页面视频的完整播放体验需要做如下声明:
页面的Activity需要声明 android:configChanges="orientation|screenSize|keyboardHidden"
2)视频为了避免闪屏和透明问题,需要如下设置
a)网页中的视频,上屏幕的时候,可能出现闪烁的情况,需要如下设置:Activity在onCreate时需要设置:
getWindow().setFormat(PixelFormat.TRANSLUCENT);//(这个对宿主没什么影响,建议声明)
b)在非硬绘手机和声明需要controller的网页上,视频切换全屏和全屏切换回页面内会出现视频窗口透明问题,需要如下设置
声明当前<item name="android:windowIsTranslucent">false</item>为不透明。
特别说明:这个视各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);
还有一些其他的配置信息 我这里就不在搬官方的介绍了。
混淆配置、APP自定义UA、Tbs视频播放器接入...等等。官方描述还是很清晰的
好啦,到这里就全部介绍完啦。希望对你帮助。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!