1. webView使用
- 应用场景:当我们的应用需要加载网页时,需要使用webView在承载目标网址。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//方式二:Webview控件跳转网页
WebView wv = findViewById(R.id.wv);
wv.loadUrl("http://www.hao123.com");
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<WebView
android:id="@+id/wv"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</WebView>
</LinearLayout>
- 问题描述:此时若网页中有Echarts图表,在部分机型上echarts图表不能被渲染加载出来,列表的滚动效果也没有,有些图片显示跑偏。 (安卓原生webview在安卓5.1版本之下canvas绘制内容加载不出来)
- 原因分析(Android内置的WebView组件的局限性):实质为webview与canvas的兼容问题。
- 解决:系统的webview有浏览器兼容问题,低端Android的webview有很多新语法都不支持,可使用x5可以拉齐webview内核。
2. webview的内核变迁及比较
Android中的WebView组件,
内存泄漏
的问题一直没有非常有效的解决方案:WebView 方案虽然使用成本低,但是存在着首次加载速度慢,内存占用高等性能问题。
(1) 在Android 4.4之前,Android手机自带的WebView(应用内嵌浏览器)使用的是WebKit内核,兼容性
和性能
都存在很大问题。
(2) 从Android4.4系统开始Chromium内核取代了Webkit内核(即webView的底层实现不一样了)。
tips:虽然使用Chromium内核后性能提升
的非常明显,鉴于Google版本帝的风格,各个版本之间的运行效率参差不齐
(安卓内置的chrome内核在加载网页和滚动的时候很卡);而且即使是chromium内核的版本,也因为要考虑兼容
以前的版本,而变得不是那么美好。也正因为如此,考虑到为了更好的体验,以及避免后续可能带来的更多麻烦,所以可选择站在巨人的肩膀上,寻找一个第三方可靠的WebView组件。
(3) 从Android5.0系统开始,WebView移植成了一个独立的apk,可以不依赖系统而独立存在和更新,可从网上搜索Android System WebView这个apk即可下载更新。
tips:升级webview(安卓5-6)只需要干两件事,即① 下载安装Android System WebView.apk ②修改系统配置的默认webview包名。第一步非常简单,第二步比较复杂,还要root。安卓7以上直接更新Android System WebView apk即可,无需root。具体步骤可参考安卓手机升级系统webview
拓展:
- 查看Android手机自带浏览器内核版本(webview版本)、Android 各个版本WebView
- 在Android5+系统,可以在不更新Android版本的情况下更新WebView内核(即在Android5+系统,webview支持安装升级):Android升级webview内核、安卓手机升级系统webview
3. 第三方WebView组件比较
(1) Crosswalk内核:Crosswalk的WebView也是基于Chromium,但是为低端、低版本设备做了良好的适配。crosswalk据说很强大,但缺点就是会让你的APK包增大很多。我还没试过,大家可以参考 如何轻松搞定Crosswalk之嵌入模式 这篇文章。
Crosswalk的缺陷:crosswalk 打包出来的app特别大,原本3M的APP也变成了几十M;APP运行一段时间之后就白屏了( 网查白屏原因:应该是内存占用太多导致的。WKWebView是一个多进程组件,Network Loading以及UI Rendering在其它进程中执行。所以UIWebView上当内存占用太大的时候,App Process会crash;而在WKWebView上当总体的内存占用比较大的时候,WebContent Process会crash,所以就白屏了。)
(2) 腾讯X5内核WebView
传统系统内核(Webview)存在适配成本高、不安全、不稳定、耗流量、速度慢、视频播放差、文件能力差等问题,这是移动应用开发商在进行Hybrid App开发时普遍面临的难题。腾讯浏览服务基于腾讯X5内核解决方案(包括内核和云服务),能够有效解决传统移动web技术面临的普遍问题,同时能极大扩展应用(Hybrid App)内浏览场景的服务能力。
-
速度快:相比系统webview的网页打开速度有30+%的提升;
-
省流量:使用云端优化技术使流量节省20+%;
-
更安全:安全问题可以在24小时内修复;
-
更稳定:经过亿级用户的使用考验,CRASH率低于0.15%;
-
兼容好:无系统内核的碎片化问题,更少的兼容性问题;
-
体验优:支持夜间模式、适屏排版、字体设置等浏览增强功能;
-
功能全:在Html5、ES6上有更完整支持;
-
更强大:集成强大的视频播放器,支持视频格式远多于系统webview;
-
视频和文件格式的支持x5内核多于系统内核
-
防劫持是x5内核的一大亮点
- 运行环境
- 手机ROM版本高于或等于2.2版本
- 手机RAM大于500M,该RAM值通过手机 /proc/meminfo 文件的MemTotal动态获取
注:如果不满足上述条件,SDK会自动切换到系统WebView,SDK使用者不用关心该切换过程。
- SDK尺寸指标:SDK提供的JAR包约250K
(3) BridgeWebView
- 结果:未成功(未能成功加载出Echarts图表,列表滚动效果也没有,图片依然跑偏),不仅在4.4及以下未显示,之前能显示的机型也不能正常渲染显示了。
- 可能原因:BridgeWebView主要用于H5和Android通信。本人的项目就单纯显示网页,出于时间考虑,既然不能正常显示Echarts图表,我就果断放弃使用该组件了,有兴趣的可以研究一下该组件,可参考 WebView的第三方组件—BridgeWebView的使用
3.2 Android 项目集成腾讯X5浏览器内核,使用 腾讯X5内核WebView 替换原生WebView
TBS服务:由腾讯QQ浏览器团队出品。支持“共享X5内核模式”和“独立下载X5内核模式”。具体可参考TBS腾讯浏览服务。
在TBS腾讯浏览服务官网下载最新SDK,根据提供的接入文档在项目中接入SDK。SDK集成和调用的主要步骤如下:
(1) SDK集成
-
下载 SDK jar 包放到工程的libs目录下
SDK导入.png - 在 jar 文件上右击后调出下拉菜单 ,点击 Add As Library... 选项;选择 jar 文件添加到的项目并等待Android Studio 进行同步;同步完成后 项目的gradle文件中多了依赖:
implementation files('libs/tbs_sdk_thirdapp_v4.3.0.39_43939_sharewithdownloadwithfile_withoutGame_obfs_20200713_223411.jar')
】即说明导入成功
(2) 权限配置:在AndroidManifest.xml配置文件中声明相关权限(加载腾讯TBS需要一定的权限,否则会失败)
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
(3) 初始化X5WebView
在加载webview之前需要初始化X5WebView,最好是在Application的onCreate()方法中,调用X5内核的初始化方法QbSdk.initX5Environment(this,null),从而提前加载x5替换webview配置。
package com.example.jackboard;
import android.app.Application;
import android.util.Log;
import com.tencent.smtt.sdk.QbSdk;
import com.tencent.smtt.sdk.TbsListener;
public class APPAplication extends Application {
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
initX5WebView();
}
/*使用腾讯x5 webview,解决安卓原生wenview不适配不同机型问题*/
private void initX5WebView() {
//搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
@Override
public void onViewInitFinished(boolean arg0) {
// TODO Auto-generated method stub
//x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
Log.d("onViewInitFinished", " onViewInitFinished is " + arg0);
if(arg0){
Log.d("onViewInitFinished", "腾讯X5内核加载成功");
}else {
Log.d("onViewInitFinished", "腾讯X5内核加载失败,使用原生安卓webview");
}
}
@Override
public void onCoreInitFinished() {
// TODO Auto-generated method stub
}
};
//x5内核初始化接口
QbSdk.initX5Environment(getApplicationContext(), cb);
}
}
备注:自定义APPAplication 继承 Application ,并在配置文件中设置application标签的name为自定义的 Application(此处即为APPAplication)。
<application
android:allowBackup="true"
android:icon="@drawable/jackboard"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme1"
android:name=".APPAplication">
</application>
(4) 将源码和XML里的相关的系统包名和类名替换为SDK里的包名和类名
- 系统内核使用的包名和类名:
package com.example.jackboard;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class WebViewNativeActivity extends AppCompatActivity {
private WebView webView;
private String url = "http://mes.uchat.com.cn/board/line?deptid=1&name=youchan";//带Echarts图表的网址
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);//隐藏状态栏
setContentView(R.layout.activity_web_native);
initViews();
initData();
}
private void initViews() {
mProgressDialog = new ProgressDialog(this);
progressBar = new ProgressBar(this);
webView = (WebView) findViewById(R.id.activity_native_webView);
Toast.makeText(this,"原生使用系统内核",Toast.LENGTH_SHORT).show();
}
private void initData() {
setAttribute(webView);
setClient();
webView.loadUrl(url);
}
private void setAttribute(WebView webView) {
WebSettings webSettings = webView.getSettings();
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
webSettings.setJavaScriptEnabled(true);//设置javascript脚本
webSettings.setSupportZoom(false);//设置支持缩放
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//设置缓存
webSettings.setDomStorageEnabled(true);//设置适应Html5,重点是这个设置
}
private void setClient(){
// 设置WebView的客户端,则就不会调用系统浏览器
webView.setWebViewClient(new WebViewClient(){
/**
* 拦截 url 跳转,在里边添加点击链接跳转或者操作
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;//返回true,立即跳转;返回false,打开网页有延时
}
/**
* 在开始加载网页时会回调
*/
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
mProgressDialog.show();
}
/**
* 在结束加载网页时会回调
*/
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
mProgressDialog.hide();
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/activity_native_webView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
- x5内核使用的包名和类名:
package com.example.jackboard;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import com.tencent.smtt.sdk.WebChromeClient;
import com.tencent.smtt.sdk.WebSettings;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.annotation.Nullable;
public class WebViewActivity extends Activity {
private WebView webView;
private String url = "http://mes.uchat.com.cn/board/line?deptid=1&name=youchan";//带Echarts图表的网址
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);//隐藏状态栏
setContentView(R.layout.activity_web);
initViews();
initData();
}
private void initViews() {
mProgressDialog = new ProgressDialog(this);
progressBar = new ProgressBar(this);
webView = (WebView)findViewById(R.id.activity_web_webView);
}
private void initData() {
setAttribute(webView);
setClient();
webView.loadUrl(url);
}
@SuppressLint("SetJavaScriptEnabled")
private void setAttribute(WebView webView) {
WebSettings webSettings = webView.getSettings();
webSettings.setSavePassword(false);
webSettings.setSaveFormData(false);
webSettings.setJavaScriptEnabled(true);//设置javascript脚本
webSettings.setSupportZoom(false);//设置支持缩放
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//设置缓存
webSettings.setDomStorageEnabled(true);//设置适应Html5,重点是这个设置
}
private void setClient(){
// 设置WebView的客户端,则就不会调用系统浏览器
webView.setWebViewClient(new WebViewClient(){
/**
* 拦截 url 跳转,在里边添加点击链接跳转或者操作
*/
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;//返回true,立即跳转;返回false,打开网页有延时
}
/**
* 在开始加载网页时会回调
*/
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
mProgressDialog.show();
}
/**
* 在结束加载网页时会回调
*/
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
mProgressDialog.hide();
}
});
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.tencent.smtt.sdk.WebView
android:id="@+id/activity_web_webView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.tencent.smtt.sdk.WebView>
</LinearLayout>
image.png
其他: web端生成的带有echarts图表的html页面,嵌入在(javaFx)webview中显示错位问题、Android 项目引入腾讯X5内核、Android 使用WebView加载含有echarts的页面,截图不显示的解决方式
网友评论