混合开发之原生嵌套h5页面(Android的webView组件 与 Echarts 适配问题)

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

拓展:

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

拓展:uniapp—webview组件浏览器内核说明uniapp集成 X5 内核-作用和局限性

传统系统内核(Webview)存在适配成本高、不安全、不稳定、耗流量、速度慢、视频播放差、文件能力差等问题,这是移动应用开发商在进行Hybrid App开发时普遍面临的难题。腾讯浏览服务基于腾讯X5内核解决方案(包括内核和云服务),能够有效解决传统移动web技术面临的普遍问题,同时能极大扩展应用(Hybrid App)内浏览场景的服务能力。

  1. 速度快:相比系统webview的网页打开速度有30+%的提升;

  2. 省流量:使用云端优化技术使流量节省20+%;

  3. 更安全:安全问题可以在24小时内修复;

  4. 更稳定:经过亿级用户的使用考验,CRASH率低于0.15%;

  5. 兼容好:无系统内核的碎片化问题,更少的兼容性问题;

  6. 体验优:支持夜间模式、适屏排版、字体设置等浏览增强功能;

  7. 功能全:在Html5、ES6上有更完整支持;

  8. 更强大:集成强大的视频播放器,支持视频格式远多于系统webview;

  9. 视频和文件格式的支持x5内核多于系统内核

  10. 防劫持是x5内核的一大亮点

  • 运行环境
  1. 手机ROM版本高于或等于2.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

参考:Android Studio 使用腾讯浏览服务(替换掉系统自带的WebView)开发指引

常见问题:SDK接入问题使用腾讯X5内核Webview有很多坑

拓展:静态集成腾讯TBS X5内核WebView,从微信提取新版30M浏览器内核打包进apk

其他: web端生成的带有echarts图表的html页面,嵌入在(javaFx)webview中显示错位问题Android 项目引入腾讯X5内核Android 使用WebView加载含有echarts的页面,截图不显示的解决方式

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271