最近遇到个需求,需要在应用内打开Office文件,Android在这方面的功能远远没有 iOS 系统方便得多.所以想到了使用腾讯浏览服务(TBS,Tencent Browsing Service); 腾讯TBS服务官网介绍
1.官网下载所需SDK
TBS下载页.jpg2.导入jar包
jar包.png然后添加add in library即可
设置ndk支持
x5暂时不提供64位so文件,为了保证64位手机能正常加载x5内核,进行以下两项设置:
打开对应module中的build.gradle文件,在文件的android{}中的defaultConfig{}里(如果没有defaultConfig{}则手动添加)添加如下配置: ndk{abiFilters "armeabi"}
image.png
3.导入so文件
image2.png在这里要注意的是,详细文档,so文件以及demo都在第一个SDK文件里面;建议两个SDK都下载下来解压查看;
image3.png
4.具体实现
需要注意的几点:
- 加载文件主要实现类是TbsReaderView,但是文档没明确写明白,在这里感谢这篇文章的帮助:简书链接
- TBS目前只支持加载本地文件。所以加载文件需要先下载到本地,然后才能进行下载。
- 显示文件的界面,退出界面以后需要销毁,否则再次加载文件无法加载成功,会一直显示加载文件进度条。
@Override
protected void onDestroy() {
super.onDestroy();
mTbsReaderView.onStop();
}
1.布局页面
<RelativeLayout
android:id="@+id/tbsView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
>
- 主要代码
mTbsReaderView = new TbsReaderView(this, this);
mRelativeLayout = findViewById(R.id.tbsView);
mRelativeLayout.addView(mTbsReaderView,new RelativeLayout.LayoutParams(-1,-1));
为什么不将 TbsReaderView 放在 layout 布局文件中,而是在代码中手动 add 进去。因为这么做会报错,提示找不到这个类。然后查看 TbsReaderView 源码,就会恍然大悟:
public TbsReaderView(Context var1, TbsReaderView.ReaderCallback var2) {
super(var1.getApplicationContext());
if(!(var1 instanceof Activity)) {
throw new RuntimeException("error: unexpect context(none Activity)");
} else {
this.d = var2;
this.a = var1;
this.e = new az(this);
}
}
3.根据url获取文件名.打开本地或者下载至本地;
private void initDoc() {
int i = docUrl.lastIndexOf("/");
String docName = docUrl.substring(i, docUrl.length());
Log.d("print", "---substring---" + docName);
//判断是否在本地/[下载/直接打开]
File docFile = new File(download, docName);
if (docFile.exists()) {
//存在本地;
Log.d("print", "本地存在");
displayFile(docFile.toString(), docName);
} else {
//本地不存在,则下载;使用的OkGo2.x;
OkGo.get(docUrl)//
.tag(this)//
.execute(new FileCallback(download, docName) { //文件下载时,可以指定下载的文件目录和文件名
@Override
public void onSuccess(File file, Call call, Response response) {
// file 即为文件数据,文件保存在指定目录
Log.d("print", "下载文件成功");
displayFile(download+file.getName(), file.getName());
Log.d("print", "" + file.getName());
}
@Override
public void downloadProgress(long currentSize, long totalSize, float progress, long networkSpeed) {
//这里回调下载进度(该回调在主线程,可以直接更新ui)
Log.d("print", "总大小---" + totalSize + "---文件下载进度---" + progress);
}
});
}
}
4.打开文件
private String tbsReaderTemp = Environment.getExternalStorageDirectory() + "/TbsReaderTemp";
private void displayFile(String filePath, String fileName) {
//增加下面一句解决没有TbsReaderTemp文件夹存在导致加载文件失败
String bsReaderTemp = tbsReaderTemp;
File bsReaderTempFile =new File(bsReaderTemp);
if (!bsReaderTempFile.exists()) {
Log.d("print","准备创建/TbsReaderTemp!!");
boolean mkdir = bsReaderTempFile.mkdir();
if(!mkdir){
Log.d("print","创建/TbsReaderTemp失败!!!!!");
}
}
Bundle bundle = new Bundle();
bundle.putString("filePath", filePath);
bundle.putString("tempPath", tbsReaderTemp);
boolean result = mTbsReaderView.preOpen(getFileType(fileName), false);
Log.d("print","查看文档---"+result);
if (result) {
mTbsReaderView.openFile(bundle);
}else{
}
}
private String getFileType(String paramString) {
String str = "";
if (TextUtils.isEmpty(paramString)) {
Log.d("print", "paramString---->null");
return str;
}
Log.d("print", "paramString:" + paramString);
int i = paramString.lastIndexOf('.');
if (i <= -1) {
Log.d("print", "i <= -1");
return str;
}
str = paramString.substring(i + 1);
Log.d("print", "paramString.substring(i + 1)------>" + str);
return str;
}
遇到的问题
- 1.TbsReader: Set reader view exception:Cannot add a null child view to a ViewGroup
TbsReaderView: OpenFile failed!
bundle.putString("filePath", filePath); 可能是文件的路径错误 检查一下filePath的路径;
- 2.插件加载失败
可能是so文件不支持;未提供x64的so
ndk {
//设置支持的SO库架构 ['arm64-v8a']
abiFilters 'armeabi', "armeabi-v7a", 'x86'
}
- 3.TbsReaderView: not supported by:XXX
原因:
1. 本身不支持这种格式,具体可查看TBS文档有详细支持文档格式列表;
2. 因为是公司的测试机,未安装微信.QQ;所以手机并没有X5的内核.TBS文档内也有说明;
image4.png
但是后面安装了微信并安装文档走了一遍流程发现还是有这个错误.在Application加了这段代码才解决的
//初始化X5内核
QbSdk.initX5Environment(this, new QbSdk.PreInitCallback() {
@Override
public void onCoreInitFinished() {
//x5内核初始化完成回调接口,此接口回调并表示已经加载起来了x5,有可能特殊情况下x5内核加载失败,切换到系统内核。
}
@Override
public void onViewInitFinished(boolean b) {
//x5內核初始化完成的回调,为true表示x5内核加载成功,否则表示x5内核加载失败,会自动切换到系统内核。
Log.e("print","加载内核是否成功:"+b);
}
});
网友评论