Android 开发学习进程0.28 腾讯TBS接入和相关问题
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接入和相关问题的更多相关文章
- Android 开发学习进程0.16 layout_weight属性 R文件关联XML Module
layout_weight属性 layout_weight属性我们常常用到,但有时候会发现它还有一些奇怪的属性,比如大多数使用时会把宽度设置成0,但要是宽度不设置成0会有什么效果? layout_we ...
- Android 开发学习进程0.19 webview 的使用
Android 中的webview android 中的webview是可以在app内部打开HTML等的网页,不必再打开浏览器,有两种实现方法,即webviewclient webChromeclie ...
- Android开发学习进程0.18 SharePreference的使用 AIDL
SharePreference SharePreference是一种持久化存储手段,使用场景很多,如第一次打开时加载的用户协议等.适合小数据单进程的应用.将数据以键值对的形式存储在XML中. 使用方式 ...
- Android 开发学习进程0.17 Android资源文件selector textview显示两种不同字体
selector 是安卓资源文件的一种,它可以使按钮等实现不同状态下的不同UI,不用在代码中实现,而使用方式有两种,一种在color文件下 创建.xml可以使按钮等字体在不同状态下的变化,其二是在dr ...
- Android 开发学习进程0.15 adb cardview framelayout 控件设置状态获取焦点
Android设备调试桥 即adb 使用adb进行无线调试的一些常用命令 adb tcpip 5555 设置调试端口为5555 防止冲突 adb shell ifconfig wlan0 查询局域网中 ...
- Android 开发学习进程0.27 kotlin使用 和viewbinding的使用
kotlin-android-extensions 插件被废弃 笔者曾经尝试写过一部分的kotlin代码 主要是项目中一些代码是kotlin完成的,其中我认为 kotlin的kotlin-androi ...
- Android 开发学习进程0.32 dwonloadmanager使用
downloadmanager时Android系统下载器,使用系统下载器可以避免用stream流读入内存可能导致的内存溢出问题.以下为downloadmanager初始化部分.apkurl为下载网络路 ...
- Android 开发学习进程0.14 Bindview recyclerview popwindow使用 window类属性使用
BindView ButterKnife 优势 绑定组件方便,使用简单 处理点击事件方便,如adapter中的viewholder 同时父组件绑定后子组件无需绑定 注意 在setcontentview ...
- Android 开发学习进程0.13 Androidstudio快捷键 xmlns
xmlns XML namespace xml命名空间 其中主要是定义xml文件定义位置 前缀有三种,android app tools 后面为唯一标识符URI android 表示为引用自安卓系统 ...
随机推荐
- 在.NetCore(C#)中使用ODP.NET Core+Dapper操作Oracle数据库
前言 虽然一直在说"去IOE化",但是在国企和政府,Oracle的历史包袱实在太重了,甚至很多业务逻辑都是写在Oracle的各种存储过程里面实现的-- 我们的系统主要的技术栈是Dj ...
- c++格式化输入输出以及操纵器的使用
C++格式化输入和输出 1,ios类中定义的格式控制标志 ios类中定义了一个数据成员:格式控制标志字,long x_flags x_flags每一位的状态值用枚举符号常量定义:如下列出常用几个 en ...
- 【bzoj 2597】[Wc2007]剪刀石头布(图论--网络流 最小费用最大流)
题目:在一些一对一游戏的比赛(如下棋.乒乓球和羽毛球的单打)中,我们经常会遇到A胜过B,B胜过C而C又胜过A的有趣情况,不妨形象的称之为剪刀石头布情况.有的时候,无聊的人们会津津乐道于统计有多少这样的 ...
- 【bzoj 1202】[HNOI2005] 狡猾的商人(图论--带权并查集+前缀和)
题意:一个账本记录了N个月以来的收入情况,现在有一个侦探员不同时间偷看到M段时间内的总收入,问这个账本是否为假账. 解法:带权并查集+前缀和. 判断账本真假是通过之前可算到的答案与当前读入的值是否 ...
- Codeforces Round #645 (Div. 2) C. Celex Update
题目链接:C.Celex Update 题意: 给你如图所示的图形,问从(x1,y1)−>(x2,y2)路径上的不同的元素和的数量是多少. 题解: 从(1,1)到(3,3) 元素和的1−2−4− ...
- C# TCP应用编程三 异步TCP应用编程
利用TcpListener和TcpClient类在同步方式下接收.发送数据以及监听客户端连接时,在操作没有完成之前一直处于阻塞状态,这对于接受.发送数据量不大的情况或者操作勇士较短的情况下是比较方便的 ...
- 国产网络损伤仪 SandStorm -- 只需要拖拽就能删除链路规则
国产网络损伤仪SandStorm可以模拟出带宽限制.时延.时延抖动.丢包.乱序.重复报文.误码.拥塞等网络状况,在实验室条件下准确可靠地测试出网络应用在真实网络环境中的性能,以帮助应用程序在上线部署前 ...
- Kubernets二进制安装(14)之flannel之SNAT规则优化
flannel之SNAT规则优化的目的是由于在K8S中的容器内,访问不同宿主机中的容器的资源的时候,日志文件会记录为宿主机的IP地址,而不是记录为容器本身自己的IP地址,建议在不同的宿主机上的容器互访 ...
- vue中子组件更新父组件
当在子组件里更改了某些信息且关闭子组件后,需要父组件更新修改后的内容,该如何操作 1.$emit触发 父组件 @add="add(val)" 子组件 this.$emit('add ...
- SPOJ VLATTICE Visible Lattice Points(莫比乌斯反演)题解
题意: 有一个\(n*n*n\)的三维直角坐标空间,问从\((0,0,0)\)看能看到几个点. 思路: 按题意研究一下就会发现题目所求为. \[(\sum_{i=1}^n\sum_{j=1}^n\su ...