集成腾讯TBS x5浏览器内核笔记

最近公司项目要实现文件预览的功能,且考虑到项目中Webview使用场景比较多,所以集成了TBS内核,API使用上和原生Webview基本一模一样,简单记录一下集成步骤

集成腾讯TBS源码

步骤
  1. 下载TBS的SDK
  2. 导入jar包和so文件
  3. 清单文件加入所需权限和Application初始化
  4. 简单展示一个http地址
  5. 视屏播放(页面视频的完整播放体验)
  6. 展示office文档
  7. 封装一个能够展示文档的控件
实现
  1. 下载TBS的SDK
    从官网TBS下载所需版本的SDK,我选用的是完整版 + 文件能力这个版本,版本具体的区别官网都有,根据自己需要选择,下载完成后有一个jar包和一个简易的Demo,目录如下
    image.png
  2. 导入jar包和so文件

    把jar包导入到libs并添加引用,复制demo中的jinLibs到项目的main目录下,完成后项目目录结构如下
    image.png
  3. 清单文件加入所需权限和Application初始化
    jni初始化,在gradle文件中的defaultconfig中添加ndk
ndk {
            abiFilters "armeabi", "armeabi-v7a", "x86", "mips"
}

在清单文件添加一下权限,运行时动态申请所需要的权限,主要是存储读写和电话权限

    <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.INTERNET" />

    <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />

    <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="com.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.google.android.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.google.android.launcher.permission.WRITE_SETTINGS" />
    <uses-permission android:name="com.htc.launcher.permission.READ_SETTINGS" />
    <uses-permission android:name="com.htc.launcher.permission.WRITE_SETTINGS" />

在Application中初始化设置

import android.app.Application;

import com.tencent.smtt.sdk.QbSdk;

/**
 * Create by chenyangqi on 2019/4/21
 * description:
 */
public class APP extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        //搜集本地tbs内核信息并上报服务器,服务器返回结果决定使用哪个内核。
        QbSdk.PreInitCallback callback = new QbSdk.PreInitCallback() {
            @Override
            public void onViewInitFinished(boolean arg) {
                //x5內核初始化完成的回调,
                // true表示x5内核加载成功,
                // false表示x5内核加载失败,会自动切换到系统内核。
            }

            @Override
            public void onCoreInitFinished() {
            }
        };

        QbSdk.initX5Environment(getApplicationContext(), callback);
    }
}

4.简单实用
和原生Webview一样的语法,如下简单展示京东商城的地址

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical">

 <ProgressBar
     android:id="@+id/progressbar"
     style="?android:attr/progressBarStyleHorizontal"
     android:layout_width="match_parent"
     android:layout_height="3dp" />

 <com.tencent.smtt.sdk.WebView
     android:id="@+id/webview"
     android:layout_width="match_parent"
     android:layout_height="match_parent" />

</LinearLayout>
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.widget.ProgressBar;

import com.tencent.smtt.export.external.interfaces.JsResult;
import com.tencent.smtt.export.external.interfaces.SslError;
import com.tencent.smtt.export.external.interfaces.SslErrorHandler;
import com.tencent.smtt.export.external.interfaces.WebResourceRequest;
import com.tencent.smtt.export.external.interfaces.WebResourceResponse;
import com.tencent.smtt.sdk.WebChromeClient;
import com.tencent.smtt.sdk.WebSettings;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebViewClient;

public class MainActivity extends AppCompatActivity {
    private ProgressBar progressBar;
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        progressBar = findViewById(R.id.progressbar);
        webView = findViewById(R.id.webview);
        initWebView();
    }

    private void initWebView() {
        WebSettings settings = webView.getSettings();           //和系统webview一样
        settings.setJavaScriptEnabled(true);                    //支持Javascript 与js交互
        settings.setJavaScriptCanOpenWindowsAutomatically(true);//支持通过JS打开新窗口
        settings.setAllowFileAccess(true);                      //设置可以访问文件
        settings.setSupportZoom(true);                          //支持缩放
        settings.setBuiltInZoomControls(true);                  //设置内置的缩放控件
        settings.setUseWideViewPort(true);                      //自适应屏幕
        settings.setSupportMultipleWindows(true);               //多窗口
        settings.setDefaultTextEncodingName("utf-8");            //设置编码格式
        settings.setAppCacheEnabled(true);
        settings.setDomStorageEnabled(true);
        settings.setAppCacheMaxSize(Long.MAX_VALUE);
        settings.setCacheMode(WebSettings.LOAD_NO_CACHE);       //缓存模式
        webView.setWebViewClient(new WebViewClient() {

            @Override
            public void onPageStarted(WebView webView, String s, Bitmap bitmap) {
                super.onPageStarted(webView, s, bitmap);
            }

            @Override
            public void onPageFinished(WebView webView, String s) {
                super.onPageFinished(webView, s);
            }

            @Override
            public boolean shouldOverrideUrlLoading(WebView webView, String url) {
                webView.loadUrl(url);
                return true;
            }

            @Override
            public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {
//                super.onReceivedSslError(webView, sslErrorHandler, sslError);
                sslErrorHandler.proceed();//忽略SSL证书错误
            }

            @Override
            public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest) {
                return super.shouldInterceptRequest(webView, webResourceRequest);
            }
        });

        webView.setWebChromeClient(new WebChromeClient() {
                                       @Override
                                       public boolean onJsAlert(WebView webView, String s, String s1, JsResult jsResult) {
                                           return super.onJsAlert(webView, s, s1, jsResult);
                                       }

                                       @Override
                                       public void onReceivedTitle(WebView webView, String s) {
                                           super.onReceivedTitle(webView, s);
                                       }

                                       @Override
                                       public void onProgressChanged(WebView webView, int progress) {
                                           super.onProgressChanged(webView, progress);
                                           progressBar.setProgress(progress); //设置进度条

                                       }
                                   }
        );
        webView.loadUrl("http://www.jd.com");
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webView != null && webView.canGoBack()) {
            if ((keyCode == KeyEvent.KEYCODE_BACK) && webView != null && webView.canGoBack()) {
                webView.goBack();
                return true;
            } else {
            }
            return true;
        } else {
            return super.onKeyDown(keyCode, event);
        }
    }
}

效果如下


image.png
  1. 视屏播放
    在WebView页面的Activity声明,实现与浏览器一样的播放体验,全屏、小窗播放、亮度音量等Control,效果如下
android:configChanges="orientation|screenSize|keyboardHidden"
image.png
6.展示office文档

注意Bundle里面的两个参数
filePath:表示要展示的本地文件的路劲
tempPath:表示TBS需要传入的一个临时存放文件的路径,创建一个目录传进去就行,保证非空就OK

public class ReadFileActivity extends AppCompatActivity implements TbsReaderView.ReaderCallback {
    private FrameLayout mFrameLayout;
    private TbsReaderView mTbsReaderView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_read_file);
        mFrameLayout = findViewById(R.id.fl_file);
        mTbsReaderView = new TbsReaderView(this, this);
        mFrameLayout.addView(mTbsReaderView);
        initReadFile();
    }

    private void initReadFile() {
        String bsReaderTemp = Environment.getExternalStorageDirectory() + "/TbsTempPath";
        File bsReaderTempFile = new File(bsReaderTemp);
        if (!bsReaderTempFile.exists()) {
            bsReaderTempFile.mkdir();
        }
        String path = "/sdcard/安卓开发规范.pdf";
        //通过bundle把文件传给x5,打开的事情交由x5处理
        Bundle bundle = new Bundle();
        bundle.putString("filePath", path);
        bundle.putString("tempPath", bsReaderTemp);
        //加载文件前的初始化工作,加载支持不同格式的插件
        boolean b = mTbsReaderView.preOpen(getFileType(path), false);
        if (b) {
            mTbsReaderView.openFile(bundle);
        }
    }

    /***
     * 获取文件类型
     *
     * @param path 文件路径
     * @return 文件的格式
     */
    private String getFileType(String path) {
        String str = "";

        if (TextUtils.isEmpty(path)) {
            return str;
        }
        int i = path.lastIndexOf('.');
        if (i <= -1) {
            return str;
        }
        str = path.substring(i + 1);
        return str;
    }

    @Override
    public void onCallBackAction(Integer integer, Object o, Object o1) {
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mTbsReaderView.onStop();
    }

}
7.TbsReaderView的简单封装,方便在XML布局中直接使用

import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.tencent.smtt.sdk.TbsReaderView;

import java.io.File;

/**
 * @author : ChenYangQi
 * date   : 2019/12/4 14:11
 * desc   : 基于TbsReaderView封装一层,便于直接在XML中使用
 */
public class FileReaderView extends FrameLayout {
    private static final String TEMP_PATH = "/TbsTempPath";
    private TbsReaderView mTbsReaderView;

    public FileReaderView(@NonNull Context context) {
        this(context, null);
    }

    public FileReaderView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FileReaderView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mTbsReaderView = new TbsReaderView(getContext(), new TbsReaderView.ReaderCallback() {
            @Override
            public void onCallBackAction(Integer integer, Object o, Object o1) {

            }
        });
        addView(mTbsReaderView);
    }

    /**
     * 展示office文档
     *
     * @param localPath 要展示的文档的本地路径
     */
    public void openFile(String localPath) {
        try {
            String bsReaderTemp = Environment.getExternalStorageDirectory() + TEMP_PATH;
            File bsReaderTempFile = new File(bsReaderTemp);
            if (!bsReaderTempFile.exists()) {
                bsReaderTempFile.mkdir();
            }
            Bundle bundle = new Bundle();
            bundle.putString("filePath", localPath);
            bundle.putString("tempPath", bsReaderTemp);
            boolean isSupportType = mTbsReaderView.preOpen(getFileType(localPath), false);
            if (isSupportType) {
                mTbsReaderView.openFile(bundle);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 释放资源,如不调用onStop,下一次打开文件,将显示上一次的文件内容
     */
    public void destroy() {
        if (mTbsReaderView != null) {
            mTbsReaderView.onStop();
        }
    }

    /***
     * 获取文件类型
     *
     * @param path 文件路径
     * @return 文件的格式
     */
    private String getFileType(String path) {
        String str = "";

        if (TextUtils.isEmpty(path)) {
            return str;
        }
        int i = path.lastIndexOf('.');
        if (i <= -1) {
            return str;
        }
        str = path.substring(i + 1);
        return str;
    }
}

使用封装的FileReaderView

public class CustomActivity extends AppCompatActivity {
    private FileReaderView fileReaderView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom);
        fileReaderView = findViewById(R.id.frv_test);
        fileReaderView.openFile("/sdcard/安卓开发规范.pdf");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        fileReaderView.destroy();
    }
}

集成腾讯TBS源码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。