TBS 的接入和使用

TBS 的接入

腾讯TBS是X5内核的升级版,可以当作webview 来打开 网页,可以以用来打开docx doc pdf 等文件,这里主要使用的是文件功能。

依赖接入 api 'com.tencent.tbs.tbssdk:sdk:43939' 这是笔者2021/2/25编辑时最新版本,最新可在官网查询。

如果依赖文件下载有问题可手动下载jia包,本地依赖包可放在 app/libs 下,文件夹可自行创建,同时在 app/src/main/jniLibs/armeabi 下存放.so 文件。

再module 的gradle文件defaultConfig下添加

 ndk {
abiFilters "armeabi", "x86", "mips", "armeabi-v7a"
}

这是为了避免64位手机不兼容的情况,强制打包。部分博客仅添加了 “armeabi” 一项。

TBS 的使用

1 在继承的application中初始化

   QbSdk.PreInitCallback cb = new QbSdk.PreInitCallback() {
@Override
public void onViewInitFinished(boolean arg0) {
//x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
Log.e(TAG, "加载内核是否成功:" + arg0);
}
@Override
public void onCoreInitFinished() {
Log.e(TAG, "加载内核是否成功:");
}
};
//x5内核初始化接口
QbSdk.initX5Environment(getApplicationContext(), cb);

这里解释下,initX5Environment初始化方法中回调是可以写做 null的,但为了验证是否成功加载内核,还是有必要重写一下方法。同时软件需要获取以下权限:

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

注意动态权限读写内存和读取手机状态的获取。

2 TBS的两种使用

第一种是弹出式框使用

  filepath = "/storage/emulated/0/aaa.docx";
HashMap<String, String> params = new HashMap<String, String>();
JSONObject jsonObject=new JSONObject();
try {
jsonObject.put("pkgName", DocxActivity.this.getApplication().getPackageName());
} catch (JSONException e) {
e.printStackTrace();
}
params.put("style", "1");
params.put("local", "true"); //进入文件查看器
params.put("memuData", jsonObject.toString());
QbSdk.openFileReader(this,filepath, params,this);

结果如图所示



文件路径我使用的是根目录,目前TBS不支持网络预览文件,因此需要下载后才能打开。hashmap的参数说明如下,style是界面风格,详细可查看官方文档,local是是否进入本地文件管理器,memuData是菜单选项。由json写入。

第二种是使用自己activity 创建自定义view,这种形式更加灵活,可定制性更强。

public class MyTbsReadView extends FrameLayout implements TbsReaderView.ReaderCallback {
private static final String TAG = "MyTbsReadView";
private TbsReaderView tbsReaderView;
private int saveTime = -1;
private Context context;
private getFilepathListener getFilepathListener;
public MyTbsReadView(@NonNull Context context) {
this(context, null, 0);
}
public MyTbsReadView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyTbsReadView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
tbsReaderView = new TbsReaderView(context, this);
this.addView(tbsReaderView, new LinearLayout.LayoutParams(-1, -1));
this.context = context;
}
public void show(){
if (getFilepathListener != null) {
getFilepathListener.getFilePath(this);
}
}
private TbsReaderView getTbsView(Context context) {
return new TbsReaderView(context, this);
}
public void display(File file){
if (file != null&& !TextUtils.isEmpty(file.toString())) {
String tempfilefolder="/storage/emulated/0/TbsReaderTemp";
File tempfile=new File(tempfilefolder);
if (!tempfile.exists()) {
boolean flag= tempfile.mkdir();
if (flag) {
Log.e(TAG, "display: success" );
} else {
Log.e(TAG, "display: faile" );
}
}
Bundle bundle =new Bundle();
bundle.putString("filePath", file.toString());
bundle.putString("tempPath", Environment.getExternalStorageDirectory()+"/"+"TbsReaderTemp");
if (tbsReaderView == null) {
this.tbsReaderView=getTbsView(context);
}
if (this.tbsReaderView.preOpen(getFileType(file.toString()),false)) {
this.tbsReaderView.openFile(bundle);
}
}else {
Log.e(TAG, "display: file path doesn't exists" );
}
}
private String getFileType(String toString) {
String str="";
if (TextUtils.isEmpty(toString)) {
return str;
}
int i=toString.lastIndexOf(".");
if (i <= -1) {
return str;
}
str=toString.substring(i+1);
return str;
}
public void setGetFilepathListener(getFilepathListener listener) {
this.getFilepathListener = listener;
}
@Override
public void onCallBackAction(Integer integer, Object o, Object o1) {
Log.e(TAG, "onCallBackAction: "+integer );
}
public void onStop(){
if (tbsReaderView != null) {
tbsReaderView.onStop();
}
}
public interface getFilepathListener {
void getFilePath(MyTbsReadView myTbsReadView);
}
}

这里是自定义view代码 。继承framelayout。使用回调填充TbsReaderView,关键代码为以下:

   Bundle bundle =new Bundle();
bundle.putString("filePath", file.toString());
bundle.putString("tempPath", Environment.getExternalStorageDirectory()+"/"+"TbsReaderTemp");
if (tbsReaderView == null) {
this.tbsReaderView=getTbsView(context);
}
if (this.tbsReaderView.preOpen(getFileType(file.toString()),false)) {
this.tbsReaderView.openFile(bundle);
}

tbsReaderView 传入bundle值,分别为文件路径和临时文件路径,需要注意的是TbsReaderTemp文件夹需要事先创建,但只要手机有腾讯系软件如QQ,微信,此文件夹会事先存在。

在activity中使用代码如下:

 filepath = "/storage/emulated/0/aaa.docx";
File myfile=new File(filepath);
Log.e(TAG, "initView: "+myfile.length() );
myTbsReadView.setGetFilepathListener(new MyTbsReadView.getFilepathListener() {
@Override
public void getFilePath(MyTbsReadView myTbsReadView) {
myTbsReadView.display(myfile);
}
});
myTbsReadView.show();

添加文件导入监听,触发时使用show函数,需要注意的是需要在activity销毁时调用组件的onStop函数,否则再次打开会失败。结果如下:

TBS使用注意事项

笔者在使用时是创建demo的方式,还是遇到了不少问题,这里需要说明下:

1需要非安全http传输设置 即 manifest中networkSecurityConfig 和usesCleartextTraffic的两个属性。 2在Android10以上非专有文件读写需要设置,常用的方法是减低限制 ,在nanifest文件中requestLegacyExternalStorage`属性设置为true

3 manifest中provider

  <!-- 非AndroidX使用 android:name="android.support.v4.content.FileProvider"-->
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_file_paths"/>
</provider>

provider_file_path文件如下

<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="" name="sdcard"/>
</paths>
</resources>

4 X5内核加载失败,具体表现为 “ not supported by:doc” 这个问题困扰笔者许久,最后的解决方式是在继承的application文件中,即初始化X5中添加

  QbSdk.setTbsListener(new TbsListener() {
@Override
public void onDownloadFinish(int i) {
}
@Override
public void onInstallFinish(int i) {
Log.e(TAG, "onInstallFinish: 内核下载安装成功" );
}
@Override
public void onDownloadProgress(int i) {
}
});
boolean needDownload = TbsDownloader.needDownload(this, TbsDownloader.DOWNLOAD_OVERSEA_TBS);
Log.e(TAG, "onCreate: "+needDownload );
if (needDownload) {
TbsDownloader.startDownload(this);
}
TUIKit.init(this, GenerateTestUserSig.SDKAPPID, new ConfigHelper().getConfigs());

在加载内核失败后重新下载,最后log提示安装成功。

Android 开发学习进程0.28 腾讯TBS接入和相关问题的更多相关文章

  1. Android 开发学习进程0.16 layout_weight属性 R文件关联XML Module

    layout_weight属性 layout_weight属性我们常常用到,但有时候会发现它还有一些奇怪的属性,比如大多数使用时会把宽度设置成0,但要是宽度不设置成0会有什么效果? layout_we ...

  2. Android 开发学习进程0.19 webview 的使用

    Android 中的webview android 中的webview是可以在app内部打开HTML等的网页,不必再打开浏览器,有两种实现方法,即webviewclient webChromeclie ...

  3. Android开发学习进程0.18 SharePreference的使用 AIDL

    SharePreference SharePreference是一种持久化存储手段,使用场景很多,如第一次打开时加载的用户协议等.适合小数据单进程的应用.将数据以键值对的形式存储在XML中. 使用方式 ...

  4. Android 开发学习进程0.17 Android资源文件selector textview显示两种不同字体

    selector 是安卓资源文件的一种,它可以使按钮等实现不同状态下的不同UI,不用在代码中实现,而使用方式有两种,一种在color文件下 创建.xml可以使按钮等字体在不同状态下的变化,其二是在dr ...

  5. Android 开发学习进程0.15 adb cardview framelayout 控件设置状态获取焦点

    Android设备调试桥 即adb 使用adb进行无线调试的一些常用命令 adb tcpip 5555 设置调试端口为5555 防止冲突 adb shell ifconfig wlan0 查询局域网中 ...

  6. Android 开发学习进程0.27 kotlin使用 和viewbinding的使用

    kotlin-android-extensions 插件被废弃 笔者曾经尝试写过一部分的kotlin代码 主要是项目中一些代码是kotlin完成的,其中我认为 kotlin的kotlin-androi ...

  7. Android 开发学习进程0.32 dwonloadmanager使用

    downloadmanager时Android系统下载器,使用系统下载器可以避免用stream流读入内存可能导致的内存溢出问题.以下为downloadmanager初始化部分.apkurl为下载网络路 ...

  8. Android 开发学习进程0.14 Bindview recyclerview popwindow使用 window类属性使用

    BindView ButterKnife 优势 绑定组件方便,使用简单 处理点击事件方便,如adapter中的viewholder 同时父组件绑定后子组件无需绑定 注意 在setcontentview ...

  9. Android 开发学习进程0.13 Androidstudio快捷键 xmlns

    xmlns XML namespace xml命名空间 其中主要是定义xml文件定义位置 前缀有三种,android app tools 后面为唯一标识符URI android 表示为引用自安卓系统 ...

随机推荐

  1. php小程序-文章发布系统

    php小程序-文章发布系统 一 项目相关视图 二 项目经验 主要用于熟悉php与mysql的相关操作 三 源码下载地址 http://files.cnblogs.com/files/qiujun/ar ...

  2. AtCoder Beginner Contest 170

    比赛链接:https://atcoder.jp/contests/abc170 A - Five Variables 题意 $5$ 个数中有 $1$ 个 $0$,判断是第几个. 代码 #include ...

  3. Redis-sentinel 哨兵(HA)

    Sentinel 介绍 Redis-Sentinel 是 Redis 官方推荐的高可用性(HA)解决方案,当用 Redis 做 Master-slave 的高可用方案时,假如Master 宕机了,Re ...

  4. kubernetes进阶(五)dashboard--WEB管理

    dashboard是k8s的可视化管理平台,是三种管理k8s集群方法之一 首先下载镜像上传到我们的私有仓库中:hdss7-200 # docker pull k8scn/kubernetes-dash ...

  5. ArcGIS制作MobileCache

    在使用ArcGIS Mobile进行二次开发时,矢量图层需要制作成MobileCache,才能在手持设备中加载. 下面介绍如何通过ArcMap制作MobileCache: 一.安装ArcGIS Mob ...

  6. codeforces 1039B Subway Pursuit【二分+随机】

    题目:戳这里 题意:一个点在[1,n]以内,我们可以进行4500次查询,每次查询之后,该点会向左或向右移动0~k步,请在4500次查询以内找到该点. 解题思路:一边二分,一边随机. 交互题似乎有好多是 ...

  7. HDU 3065 病毒侵袭持续中(AC自动机 模板)题解

    题意:给出主串中每个模式串的个数 思路:毒瘤出题人多组数据没说给的是多组数据. 板子: struct Aho{ struct state{ int next[130]; int fail, cnt; ...

  8. keras自定义网络层

    在深度学习领域,Keras是一个高度封装的库并被广泛应用,可以通过调用其内置网络模块(各种网络层)实现针对性的模型结构:当所需要的网络层功能不被包含时,则需要通过自定义网络层或模型实现. 如何在ker ...

  9. Python errors All In One

    Python errors All In One SyntaxError: invalid character in identifier \u200b, ZERO WIDTH SPACE https ...

  10. Mac 外接 Dell 4K 显示器字体模糊解决办法

    Mac 外接 Dell 4K 显示器字体模糊解决办法 mac mini mbp 2020 refs https://zhuanlan.zhihu.com/p/52100804 xgqfrms 2012 ...