美文网首页
混合开发之原生嵌套h5页面(Android的webView组件

混合开发之原生嵌套h5页面(Android的webView组件

作者: 瑟闻风倾 | 来源:发表于2020-10-13 10:22 被阅读0次

    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的页面,截图不显示的解决方式

    相关文章

      网友评论

          本文标题:混合开发之原生嵌套h5页面(Android的webView组件

          本文链接:https://www.haomeiwen.com/subject/fjbnyktx.html